IAAAAAAAAAAAA
This commit is contained in:
parent
30dfb5a6cd
commit
84605fdf60
|
|
@ -1,19 +1,227 @@
|
|||
package backend;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
|
||||
public class AutoPlayer {
|
||||
|
||||
|
||||
/**
|
||||
* returns the best Move to try on provided board for active player
|
||||
* @param board
|
||||
* @return
|
||||
*/
|
||||
public Move computeBestMove(Board board) {
|
||||
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private int MAX_DEPTH = 3;
|
||||
private int[][] PAWN_TABLE = {
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0 },
|
||||
{ 5, 5, 5, -5, -5, 5, 5, 5 },
|
||||
{ 1, 1, 2, 3, 3, 2, 1, 1 },
|
||||
{ 0, 0, 0, 2, 2, 0, 0, 0 },
|
||||
{ 1, 1, 1, 0, 0, 1, 1, 1 },
|
||||
{ 2, 2, 2, -2, -2, 2, 2, 2 },
|
||||
{ 5, 5, 5, 5, 5, 5, 5, 5 },
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0 }
|
||||
};
|
||||
private int[][] KNIGHT_TABLE = {
|
||||
{-50,-40,-30,-30,-30,-30,-40,-50},
|
||||
{-40,-20, 0, 0, 0, 0,-20,-40},
|
||||
{-30, 0, 10, 15, 15, 10, 0,-30},
|
||||
{-30, 5, 15, 20, 20, 15, 5,-30},
|
||||
{-30, 0, 15, 20, 20, 15, 0,-30},
|
||||
{-30, 5, 10, 15, 15, 10, 5,-30},
|
||||
{-40,-20, 0, 5, 5, 0,-20,-40},
|
||||
{-50,-40,-30,-30,-30,-30,-40,-50}
|
||||
};
|
||||
private int[][] BISHOP_TABLE = {
|
||||
{-20,-10,-10,-10,-10,-10,-10,-20},
|
||||
{-10, 5, 0, 0, 0, 0, 5,-10},
|
||||
{-10, 10, 10, 10, 10, 10, 10,-10},
|
||||
{-10, 0, 10, 10, 10, 10, 0,-10},
|
||||
{-10, 5, 5, 10, 10, 5, 5,-10},
|
||||
{-10, 0, 5, 10, 10, 5, 0,-10},
|
||||
{-10, 0, 0, 0, 0, 0, 0,-10},
|
||||
{-20,-10,-10,-10,-10,-10,-10,-20}
|
||||
};
|
||||
private int[][] ROOK_TABLE = {
|
||||
{ 0, 0, 0, 5, 5, 0, 0, 0 },
|
||||
{ -5, 0, 0, 0, 0, 0, 0, -5 },
|
||||
{ -5, 0, 0, 0, 0, 0, 0, -5 },
|
||||
{ -5, 0, 0, 0, 0, 0, 0, -5 },
|
||||
{ -5, 0, 0, 0, 0, 0, 0, -5 },
|
||||
{ -5, 0, 0, 0, 0, 0, 0, -5 },
|
||||
{ 5, 10, 10, 10, 10, 10, 10, 5 },
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0 }
|
||||
};
|
||||
private int[][] QUEEN_TABLE = {
|
||||
{-20,-10,-10, -5, -5,-10,-10,-20},
|
||||
{-10, 0, 0, 0, 0, 0, 0,-10},
|
||||
{-10, 0, 5, 5, 5, 5, 0,-10},
|
||||
{ -5, 0, 5, 5, 5, 5, 0, -5},
|
||||
{ 0, 0, 5, 5, 5, 5, 0, -5},
|
||||
{-10, 5, 5, 5, 5, 5, 0,-10},
|
||||
{-10, 0, 5, 0, 0, 0, 0,-10},
|
||||
{-20,-10,-10, -5, -5,-10,-10,-20}
|
||||
};
|
||||
private int[][] KING_TABLE = {
|
||||
{-30,-40,-40,-50,-50,-40,-40,-30},
|
||||
{-30,-40,-40,-50,-50,-40,-40,-30},
|
||||
{-30,-40,-40,-50,-50,-40,-40,-30},
|
||||
{-30,-40,-40,-50,-50,-40,-40,-30},
|
||||
{-20,-30,-30,-40,-40,-30,-30,-20},
|
||||
{-10,-20,-20,-20,-20,-20,-20,-10},
|
||||
{ 20, 20, 0, 0, 0, 0, 20, 20},
|
||||
{ 20, 30, 10, 0, 0, 10, 30, 20}
|
||||
};
|
||||
public Move computeBestMove(ArrayList<ArrayList<Piece>> board, boolean isWhiteTurn) {
|
||||
Move bestMove = null;
|
||||
int bestScore = isWhiteTurn ? Integer.MIN_VALUE : Integer.MAX_VALUE;
|
||||
|
||||
ArrayList<Move> allMoves = getAllLegalMoves(board, isWhiteTurn);
|
||||
|
||||
for (Move move : allMoves) {
|
||||
ArrayList<ArrayList<Piece>> simulatedBoard = simulateMove(board, move);
|
||||
int score = minimax(simulatedBoard, MAX_DEPTH - 1, !isWhiteTurn);
|
||||
|
||||
if (isWhiteTurn && score > bestScore) {
|
||||
bestScore = score;
|
||||
bestMove = move;
|
||||
} else if (!isWhiteTurn && score < bestScore) {
|
||||
bestScore = score;
|
||||
bestMove = move;
|
||||
}
|
||||
}
|
||||
|
||||
return bestMove;
|
||||
}
|
||||
|
||||
private int minimax(ArrayList<ArrayList<Piece>> board, int depth, boolean isWhiteTurn) {
|
||||
if (depth == 0) {
|
||||
return evaluateBoard(board);
|
||||
}
|
||||
|
||||
ArrayList<Move> allMoves = getAllLegalMoves(board, isWhiteTurn);
|
||||
if (allMoves.isEmpty()) return evaluateBoard(board); // checkmate or stalemate
|
||||
|
||||
int bestScore = isWhiteTurn ? Integer.MIN_VALUE : Integer.MAX_VALUE;
|
||||
|
||||
for (Move move : allMoves) {
|
||||
ArrayList<ArrayList<Piece>> simulatedBoard = simulateMove(board, move);
|
||||
int score = minimax(simulatedBoard, depth - 1, !isWhiteTurn);
|
||||
|
||||
if (isWhiteTurn) {
|
||||
bestScore = Math.max(bestScore, score);
|
||||
} else {
|
||||
bestScore = Math.min(bestScore, score);
|
||||
}
|
||||
}
|
||||
|
||||
return bestScore;
|
||||
}
|
||||
|
||||
private int evaluateBoard(ArrayList<ArrayList<Piece>> board) {
|
||||
int score = 0;
|
||||
|
||||
for (int y = 0; y < 8; y++) {
|
||||
for (int x = 0; x < 8; x++) {
|
||||
Piece p = board.get(y).get(x);
|
||||
if (p != null) {
|
||||
int value = getPieceValue(p.getType());
|
||||
int positionalBonus = getPositionalBonus(p, x, y);
|
||||
|
||||
if (p.isWhite()) {
|
||||
score += value + positionalBonus;
|
||||
} else {
|
||||
score -= value + positionalBonus; // subtract opponent's bonus too
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return score;
|
||||
}
|
||||
|
||||
private int getPieceValue(PieceType type) {
|
||||
switch (type) {
|
||||
case Pawn:
|
||||
return 10;
|
||||
case Knight:
|
||||
return 30;
|
||||
case Bishop:
|
||||
return 30;
|
||||
case Rook:
|
||||
return 50;
|
||||
case Queen:
|
||||
return 90;
|
||||
case King:
|
||||
return 900;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private ArrayList<ArrayList<Piece>> simulateMove(ArrayList<ArrayList<Piece>> board, Move move) {
|
||||
ArrayList<ArrayList<Piece>> newBoard = deepCopyBoard(board);
|
||||
|
||||
Piece piece = newBoard.get(move.fromY).get(move.fromX);
|
||||
newBoard.get(move.fromY).set(move.fromX, null);
|
||||
piece.x = move.toX;
|
||||
piece.y = move.toY;
|
||||
newBoard.get(move.toY).set(move.toX, piece);
|
||||
|
||||
return newBoard;
|
||||
}
|
||||
|
||||
private ArrayList<ArrayList<Piece>> deepCopyBoard(ArrayList<ArrayList<Piece>> original) {
|
||||
ArrayList<ArrayList<Piece>> copy = new ArrayList<>();
|
||||
for (ArrayList<Piece> row : original) {
|
||||
ArrayList<Piece> newRow = new ArrayList<>();
|
||||
for (Piece p : row) {
|
||||
if (p != null) {
|
||||
newRow.add(PieceCreation.createPiece(p.getX(), p.getY(), p.getType(), p.isWhite()));
|
||||
} else {
|
||||
newRow.add(null);
|
||||
}
|
||||
}
|
||||
copy.add(newRow);
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
private ArrayList<Move> getAllLegalMoves(ArrayList<ArrayList<Piece>> board, boolean isWhiteTurn) {
|
||||
ArrayList<Move> legalMoves = new ArrayList<>();
|
||||
|
||||
for (ArrayList<Piece> row : board) {
|
||||
for (Piece p : row) {
|
||||
if (p != null && p.isWhite() == isWhiteTurn) {
|
||||
ArrayList<ArrayList<Boolean>> moves = p.getPossibleMoves(board);
|
||||
for (int y = 0; y < 8; y++) {
|
||||
for (int x = 0; x < 8; x++) {
|
||||
if (moves.get(y).get(x)) {
|
||||
legalMoves.add(new Move(p.getX(), p.getY(), x, y));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return legalMoves;
|
||||
}
|
||||
|
||||
private int getPositionalBonus(Piece piece, int x, int y) {
|
||||
if (!piece.isWhite()) {
|
||||
y = 7 - y; // mirror for black
|
||||
}
|
||||
|
||||
switch (piece.getType()) {
|
||||
case Pawn:
|
||||
return PAWN_TABLE[y][x];
|
||||
case Knight:
|
||||
return KNIGHT_TABLE[y][x];
|
||||
case Bishop:
|
||||
return BISHOP_TABLE[y][x];
|
||||
case Rook:
|
||||
return ROOK_TABLE[y][x];
|
||||
case Queen:
|
||||
return QUEEN_TABLE[y][x];
|
||||
case King:
|
||||
return KING_TABLE[y][x];
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -240,8 +240,46 @@ public class Board {
|
|||
}
|
||||
|
||||
public void playMove(Move move) {
|
||||
//TODO
|
||||
int xm = move.getFromX();
|
||||
int ym = move.getFromY();
|
||||
int x = move.getToX();
|
||||
int y = move.getToY();
|
||||
boardHistory.add(new BoardHistory(board,turnNumber,turnColor));
|
||||
Piece pieceToMove = this.board.get(ym).get(xm);
|
||||
boolean isCastlingMove = pieceToMove.getType() == PieceType.King && Math.abs(x - xm) == 2;
|
||||
|
||||
//check for castling mode:
|
||||
if (isCastlingMove) {
|
||||
|
||||
//kingside
|
||||
if (x > xm) {
|
||||
Piece rook = board.get(ym).get(7);
|
||||
board.get(ym).set(5, rook);
|
||||
board.get(ym).set(7, null);
|
||||
if (rook != null) {
|
||||
rook.x = 5;
|
||||
rook.setMoved(true);
|
||||
}
|
||||
}
|
||||
if (x < xm) {
|
||||
Piece rook = board.get(ym).get(0);
|
||||
board.get(ym).set(3, rook);
|
||||
board.get(ym).set(0, null);
|
||||
if (rook != null) {
|
||||
rook.x = 3;
|
||||
rook.setMoved(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.setPiece(x,y,pieceToMove.getType(),pieceToMove.isWhite());
|
||||
Piece movedPiece = this.getPiece(x, y);
|
||||
if (movedPiece != null) {
|
||||
movedPiece.setMoved(true);
|
||||
}
|
||||
board.get(ym).set(xm,null);
|
||||
this.turnColor = !this.turnColor;
|
||||
this.turnNumber +=1;
|
||||
}
|
||||
|
||||
public void setBoard(ArrayList<ArrayList<Piece>> board) {
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ public class Game extends Thread {
|
|||
|
||||
private void aiPlayerTurn() {
|
||||
if(isAITurn()) {
|
||||
board.playMove(aiPlayer.computeBestMove(new Board(board)));
|
||||
board.playMove(aiPlayer.computeBestMove(board.getBoard(),board.isTurnWhite()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,24 +1,34 @@
|
|||
package backend;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class Move {
|
||||
private int x;
|
||||
private int y;
|
||||
|
||||
|
||||
public Move(int x, int y) {
|
||||
this.x=x;
|
||||
this.y=y;
|
||||
public int fromX, fromY, toX, toY;
|
||||
|
||||
public Move(int fromX, int fromY, int toX, int toY) {
|
||||
this.fromX = fromX;
|
||||
this.fromY = fromY;
|
||||
this.toX = toX;
|
||||
this.toY = toY;
|
||||
}
|
||||
|
||||
public int getFromX() {
|
||||
return fromX;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public int getFromY() {
|
||||
return fromY;
|
||||
}
|
||||
|
||||
}
|
||||
public int getToX() {
|
||||
return toX;
|
||||
}
|
||||
|
||||
public int getToY() {
|
||||
return toY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "(" + fromX + "," + fromY + ") → (" + toX + "," + toY + ")";
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue