From 00afb304a1116a1e8b91794846d9f45608e3d956 Mon Sep 17 00:00:00 2001 From: jwb11006 Date: Sat, 30 Apr 2016 14:31:50 -0400 Subject: [PATCH] Minimax algorithm now considers if a piece is in a jump sequence, still not convinced it works though --- src/controller/Game.java | 145 +++++++++++++++++++----------- src/controller/GameConstants.java | 2 +- src/model/Board.java | 38 +++----- src/test/BoardTest.java | 1 - src/test/GameTest.java | 1 - 5 files changed, 104 insertions(+), 83 deletions(-) diff --git a/src/controller/Game.java b/src/controller/Game.java index cdb354f..4555ee3 100755 --- a/src/controller/Game.java +++ b/src/controller/Game.java @@ -50,7 +50,7 @@ public void requestMove(Move move) { /* If the game is not in the middle of a jump sequence, move the thunk */ if (!inJumpSequence) { - Move thunkMove = getMinimaxMove(GameConstants.MAX_SEARCH_DEPTH); + Move thunkMove = getMinimaxMove(GameConstants.MAX_SEARCH_DEPTH, inJumpSequence); if (thunkMove != null) { if (thunkMove.isJump()) inJumpSequence = true; @@ -62,8 +62,8 @@ public void requestMove(Move move) { gamePanel.movePiece(thunkMove); while (inJumpSequence) { - thunkMove = getMinimaxMove(GameConstants.MAX_SEARCH_DEPTH); - System.out.println("REPEATING MOVE"); + thunkMove = getMinimaxMove(GameConstants.MAX_SEARCH_DEPTH, inJumpSequence); + if (thunkMove != null) { if (movePromotesPiece(thunkMove)) { inJumpSequence = false; @@ -104,70 +104,107 @@ public Move getThunkMove() { return null; } } - - public Move getMinimaxMove(int depth, boolean currentlyIsInJumpSequence) { - // need to store the jump sequence at each call stack - Move bestMove = null; + + public Move getMinimaxMove(int depth, boolean inJumpSequence) { + ArrayList boardFrontier = null; + ArrayList moveFrontier = null; + ArrayList moveScores = new ArrayList(); + if (inJumpSequence) { - ArrayList boardFrontier = board.generateJumpFrontierForPiece(board.getLastPieceMoved()); - ArrayList moveFrontier = board.generateJumpMovesForPiece(board.getLastPieceMoved()); - ArrayList moveScores = new ArrayList(); + /* Generate the frontier only for the piece that just moves */ + boardFrontier = board.generateJumpFrontierForPiece(board.getLastPieceMoved()); + moveFrontier = board.generateJumpMovesForPiece(board.getLastPieceMoved()); - Color otherColor = - } - else { - ArrayList boardFrontier = board.generateFrontier(GameConstants.THUNK_COLOR); - ArrayList moveFrontier = board.generateAllMoves(GameConstants.THUNK_COLOR); - ArrayList moveScores = new ArrayList(); - - Color otherColor = GameConstants.THUNK_COLOR == Color.BLACK ? - Color.WHITE : Color.BLACK; - // Recurse for each one here - for (Board b : boardFrontier) { - moveScores.add(this.getMinimaxScore(otherColor, b, depth)); + /* If we can't jump anymore, we can't make a move */ + if (boardFrontier.isEmpty()) { + return null; } - - int maxScore = Integer.MIN_VALUE; - - - for (int i = 0; i < moveScores.size(); ++i) { - if (moveScores.get(i) > maxScore) { - bestMove = moveFrontier.get(i); - maxScore = moveScores.get(i); - } + + } else { + /* Generate the frontier for all pieces */ + boardFrontier = board.generateFrontier(GameConstants.THUNK_COLOR); + moveFrontier = board.generateAllMoves(GameConstants.THUNK_COLOR); + System.out.println("Board frontier size: " + boardFrontier.size()); + System.out.println("Move frontier size: " + moveFrontier.size()); + } + + Color nextColor; + /* Determine the next color to move */ + if (GameConstants.THUNK_COLOR == Color.BLACK && !inJumpSequence) { + nextColor = Color.WHITE; + } else { + nextColor = Color.BLACK; + } + + /* Calculate the minimax score for each board in the frontier */ + for (Board b : boardFrontier) { + moveScores.add(this.getMinimaxScore(nextColor, b, depth, inJumpSequence)); + } + + /* Determine the maximum minimax score and which move led to that score */ + int maxScore = Integer.MIN_VALUE; + Move bestMove = null; + + for (int i = 0; i < moveScores.size(); ++i) { + //System.out.println("score[" + i + "] = " + moveScores.get(i)); + if (moveScores.get(i) > maxScore) { + //System.out.println("Best move is " + i); + bestMove = moveFrontier.get(i); + maxScore = moveScores.get(i); } } + return bestMove; } - public int getMinimaxScore(Color color, Board b, int depth) { + public int getMinimaxScore(Color color, Board b, int depth, boolean inJumpSequence) { + ArrayList boardFrontier; + ArrayList moveScores = new ArrayList(); + if (inJumpSequence) { + /* Generate the frontier only for the piece that just moves */ + boardFrontier = b.generateJumpFrontierForPiece(b.getLastPieceMoved()); + /* If we can't jump anymore, get out of the jump sequence */ + if (boardFrontier.isEmpty()) { + inJumpSequence = false; + } + } else { + /* Generate the frontier for all pieces */ + boardFrontier = b.generateFrontier(color); + } + + /* If we have reached the maximum depth or an end state for the gam */ + if (depth == 0 || b.getBlackPieces() == 0 || b.getWhitePieces() == 0 + || boardFrontier.size() == 0) { + Color otherColor = (color == Color.BLACK ? Color.WHITE : Color.BLACK); + return b.getHeuristic(otherColor); + } + + Color nextColor; + /* Determine the next color to move */ + if (GameConstants.THUNK_COLOR == Color.BLACK && !inJumpSequence) { + nextColor = Color.WHITE; + } else { + nextColor = Color.BLACK; + } + + for (Board board : boardFrontier) { + int moveScore = getMinimaxScore(nextColor, board, depth - 1, inJumpSequence); + moveScores.add(moveScore); + } + + if (color == GameConstants.THUNK_COLOR) { + /* Since these scores are obtained from when it is the other + * player's turn, we want to minimize....I think + */ + return Collections.max(moveScores); } else { - ArrayList boardFrontier = b.generateFrontier(color); - if (depth == 0 || b.getBlackPieces() == 0 || b.getWhitePieces() == 0 - || boardFrontier.size() == 0) { - Color otherColor = color == Color.BLACK ? Color.WHITE : Color.BLACK; - return b.getHeuristic(otherColor); - } - - ArrayList moveScores = new ArrayList(); - - for (Board board : boardFrontier) { - Color nextColor = color == Color.BLACK ? Color.WHITE : Color.BLACK; - moveScores.add(getMinimaxScore(nextColor, board, depth - 1)); - } - - if (color == GameConstants.THUNK_COLOR) { - // Maximize - return Collections.max(moveScores); - } - else { - // Minimize - return Collections.min(moveScores); - } + // Minimize + return Collections.min(moveScores); } + } public void notifyClientWin() { diff --git a/src/controller/GameConstants.java b/src/controller/GameConstants.java index ec88811..d4f3895 100644 --- a/src/controller/GameConstants.java +++ b/src/controller/GameConstants.java @@ -8,5 +8,5 @@ public class GameConstants { public static final Color THUNK_COLOR = Color.WHITE; public static final Color USER_COLOR = Color.BLACK; public static final int MAX_PASSIVE_MOVES = 50; - public static final int MAX_SEARCH_DEPTH = 2; + public static final int MAX_SEARCH_DEPTH = 4; } diff --git a/src/model/Board.java b/src/model/Board.java index 96f74c5..4dac958 100755 --- a/src/model/Board.java +++ b/src/model/Board.java @@ -153,38 +153,24 @@ public ArrayList generateFrontier(Color color) { */ public ArrayList generateFrontierFromRegularMoves(Color color) { ArrayList frontier = new ArrayList(); - for (int i = 0; i < BOARD_SIZE; ++i) { - for (int j = 0; j < BOARD_SIZE; ++j) { - Piece p = this.representation[i][j]; - if(null != p && p.getColor() == color) { - ArrayList moves = generateRegularMovesForPiece(this.representation[i][j]); - for (Move move : moves) { - Board board = new Board(this); - board.movePiece(move); - frontier.add(board); - } - } - } + ArrayList moves = generateAllRegularMoves(color); + for (Move move : moves) { + Board board = new Board(this); + board.movePiece(move); + frontier.add(board); } - return frontier; + return frontier; } public ArrayList generateFrontierFromJumps(Color color) { ArrayList frontier = new ArrayList(); - for (int i = 0; i < BOARD_SIZE; ++i) { - for (int j = 0; j < BOARD_SIZE; ++j) { - Piece p = this.representation[i][j]; - if (null != p && p.getColor() == color) { - ArrayList jump_moves = generateJumpMovesForPiece(this.representation[i][j]); - for (Move jump : jump_moves) { - Board board = new Board(this); - board.movePiece(jump); - frontier.add(board); - } - } - } + ArrayList moves = generateAllJumpMoves(color); + for (Move move : moves) { + Board board = new Board(this); + board.movePiece(move); + frontier.add(board); } - return frontier; + return frontier; } public ArrayList generateMovesForPiece(Piece p) { diff --git a/src/test/BoardTest.java b/src/test/BoardTest.java index 7a178b8..8dea1b5 100755 --- a/src/test/BoardTest.java +++ b/src/test/BoardTest.java @@ -1,5 +1,4 @@ package test; - import model.Board; public class BoardTest { diff --git a/src/test/GameTest.java b/src/test/GameTest.java index fffe6c2..1094f59 100644 --- a/src/test/GameTest.java +++ b/src/test/GameTest.java @@ -6,7 +6,6 @@ import controller.Game; import model.Board; -import model.Color; import view.CheckersWindow; public class GameTest {