diff --git a/src/Board.java b/src/Board.java index 0722d8c..26b0b63 100644 --- a/src/Board.java +++ b/src/Board.java @@ -17,11 +17,15 @@ public class Board { // new Color() takes in an integer representing the color // Colors are represented in hexadecimal, so we can write the hex literal by prefixing the color code with 0x static final Color BLACK = new Color(0x6c595c); - static final Color WHITE = new Color(0xab9b8e); + static final Color WHITE = new Color(0x847875); + static final Color HIGHLIGHT = new Color(0xab9b8e7f, true); + static final Color MOVE_HIGHLIGHT = new Color(0xafb381); + static final Color CAPTURE_HIGHLIGHT = new Color(0xb65c5f); King blackKing; King whiteKing; final DrawingPanel panel; final Graphics graphics; + public boolean aiThinking = false; // The board is a two-dimensional array of nullable pieces Piece[][] board; @@ -59,6 +63,9 @@ public class Board { } public void setup() { + // Clear move history + moveHistory.clear(); + // Initialize board board = new Piece[BOARD_SIZE][BOARD_SIZE]; @@ -167,6 +174,7 @@ public class Board { setup(); return; } + if (aiThinking) return; // Get board coordinate of mouse click BoardCoordinate coordinate = new ScreenCoordinate(x, y).toBoard(); // If there's no piece there, return @@ -184,6 +192,7 @@ public class Board { } void handleMouseUp(int x, int y) { + if (aiThinking) return; // Get board coordinate of mouse release BoardCoordinate newCoordinate = new ScreenCoordinate(x, y).toBoard(); // Only do something if new coordinate is different from the originating coordinate @@ -196,12 +205,18 @@ public class Board { move(legalMove); setLastMovedPieceAsMoved(); checkForCheckmate(); + // Clear dragging + dragging = null; + // Redraw without dragging + draw(); if (!isGameOver) { - move(ChessAI.findBestMove(this)); - setLastMovedPieceAsMoved(); - checkForCheckmate(); + try { + ChessAI.move(this); + } catch (Exception e) { + System.out.println(e); + } + return; } - break; } } } @@ -232,7 +247,7 @@ public class Board { break; } } - } else if (getAllLegalMoves(movedPiece.black).isEmpty()) { + } else if (getAllLegalMoves(!movedPiece.black).isEmpty()) { isGameOver = true; isStalemate = true; } @@ -264,14 +279,14 @@ public class Board { for (int x = y % 2; x < BOARD_SIZE; x += 2) drawRect(x, y); if (dragging != null) { - graphics.setColor(new Color(0, 128, 0, 128)); + graphics.setColor(HIGHLIGHT); for (Move legalMove : legalMoves) drawRect(legalMove.to); if (mousePosition != null) { BoardCoordinate hovering = mousePosition.toBoard(); for (Move legalMove : legalMoves) { if (legalMove.to.equals(hovering)) { - graphics.setColor(get(hovering) == null ? new Color(0, 0, 255, 128) : new Color(255, 0, 0, 128)); + graphics.setColor(get(hovering) == null ? MOVE_HIGHLIGHT : CAPTURE_HIGHLIGHT); drawRect(mousePosition.toBoard()); break; } @@ -283,6 +298,10 @@ public class Board { forEachPiece((boardCoordinate, piece) -> { // If piece is the one being dragged, render it at the mouse position // Otherwise, render it at the center of the board tile + if (piece instanceof King && piece.isInCheck(this)) { + graphics.setColor(CAPTURE_HIGHLIGHT); + drawRect(boardCoordinate); + } piece.draw(graphics, panel, boardCoordinate.equals(dragging) ? mousePosition : boardCoordinate.toScreen()); }); diff --git a/src/ChessAI.java b/src/ChessAI.java index 9d3c1cd..c047b01 100644 --- a/src/ChessAI.java +++ b/src/ChessAI.java @@ -1,15 +1,39 @@ import java.util.ArrayList; import java.util.Collections; +import java.util.concurrent.Callable; +import java.util.concurrent.Future; +import java.util.concurrent.FutureTask; public class ChessAI { private static final int MAX_DEPTH = 3; + public static FutureTask move(Board board) { + Callable callable = new Callable<>() { + @Override + public Void call() throws Exception { + board.aiThinking = true; + Move move = findBestMove(board); + board.move(move); + board.setLastMovedPieceAsMoved(); + board.checkForCheckmate(); + board.draw(); + board.aiThinking = false; + return null; + } + }; + FutureTask future = new FutureTask<>(callable); + Thread thread = new Thread(future); + thread.start(); + return future; + } + public static Move findBestMove(Board board) { int bestScore = Integer.MIN_VALUE; - Move bestMove = null; ArrayList legalMoves = board.getAllLegalMoves(true); + Collections.shuffle(legalMoves); + Move bestMove = legalMoves.get(0); for (Move move : legalMoves) { board.move(move); int score = minimax(board, MAX_DEPTH, Integer.MIN_VALUE, Integer.MAX_VALUE, false); diff --git a/src/King.java b/src/King.java index 36e62b4..acce730 100644 --- a/src/King.java +++ b/src/King.java @@ -28,8 +28,8 @@ public class King extends Piece { rightRook instanceof Rook && !rightRook.moved && board.get(position.x + 1, position.y) == null && - board.get(position.x + 2, position.y) == null && - !isInCheck(board) + board.get(position.x + 2, position.y) == null // && + // !isInCheck(board) ) { // TODO: Does not take into account squares in castling path being threatened Move rightCastle = new Move(position, new BoardCoordinate(position.x + 2, position.y)); @@ -46,8 +46,8 @@ public class King extends Piece { !leftRook.moved && board.get(position.x - 1, position.y) == null && board.get(position.x - 2, position.y) == null && - board.get(position.x - 3, position.y) == null && - !isInCheck(board) + board.get(position.x - 3, position.y) == null // && + // !isInCheck(board) ) { // TODO: Does not take into account squares in castling path being threatened Move leftCastle = new Move(position, new BoardCoordinate(position.x - 2, position.y)); diff --git a/src/Pawn.java b/src/Pawn.java index 8974601..d719ace 100644 --- a/src/Pawn.java +++ b/src/Pawn.java @@ -24,7 +24,7 @@ public class Pawn extends Piece { if (board.get(position.x + 1, position.y + 1) != null) { possibleMoves.add(new Move(position, new BoardCoordinate(position.x + 1,position.y + 1))); } - for (Move move : possibleMoves) move.isPromotion = position.y + 1 == 0; + for (Move move : possibleMoves) move.isPromotion = position.y + 1 == Board.BOARD_SIZE - 1; } else { if (board.get(position.x, position.y - 1) == null) { possibleMoves.add(new Move(position, new BoardCoordinate(position.x, position.y - 1))); diff --git a/src/Piece.java b/src/Piece.java index c770688..57fdc6f 100644 --- a/src/Piece.java +++ b/src/Piece.java @@ -61,7 +61,7 @@ public abstract class Piece { outer: for (int y = 0; y < Board.BOARD_SIZE; y++) { for (int x = 0; x < Board.BOARD_SIZE; x++) { Piece piece = board.get(x, y); - if (piece == null || piece.black == black || piece instanceof King) continue; + if (piece == null || piece.black == black) continue; ArrayList legalMoves = piece.getLegalMoves(new BoardCoordinate(x, y), board, false); for (Move legalMove : legalMoves) { Piece pieceAtMove = board.get(legalMove.to);