diff --git a/src/controller/Game.java b/src/controller/Game.java index 51dd3ef..6340558 100755 --- a/src/controller/Game.java +++ b/src/controller/Game.java @@ -1,11 +1,15 @@ package controller; import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedList; +import java.util.Queue; import model.Board; import model.Color; import model.Location; import model.Move; +import model.Type; import view.GamePanel; public class Game { @@ -21,16 +25,31 @@ public Game(Board board) { /* Either the server or the user will request a move */ public void requestMove(Move move) { + + /* If this is the first jump of the jump sequence */ + if (move.isJump() && !inJumpSequence) { + inJumpSequence = true; + } + + if (movePromotesPiece(move)) { + inJumpSequence = false; + } + board.movePiece(move); gamePanel.movePiece(move); + + if (board.getMovesSinceCapture() > GameConstants.MAX_PASSIVE_MOVES) { + gamePanel.displayMessage("It's a tie! Be more aggressive next time."); + // Disable UI here + } + /* try { Thread.sleep(500); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } - /* If this is the first jump of the jump sequence */ - if (move.isJump() && !inJumpSequence) inJumpSequence = true; + */ /* If the piece that jumped has no more jumps */ if (move.isJump() && getAvailableMoves(move.destination).isEmpty()) @@ -39,23 +58,40 @@ public void requestMove(Move move) { /* If the game is not in the middle of a jump sequence, move the thunk */ if (!inJumpSequence) { - Move thunkMove = getThunkMove(); - board.movePiece(thunkMove); - gamePanel.movePiece(thunkMove); - - if (thunkMove.isJump()) inJumpSequence = true; - - while (inJumpSequence) { - thunkMove = getThunkMove(); - if (thunkMove != null) { - board.movePiece(thunkMove); - gamePanel.movePiece(thunkMove); - } else { + Move thunkMove = getMinimaxMove(GameConstants.MAX_SEARCH_DEPTH); + if (thunkMove != null) { + if (thunkMove.isJump()) inJumpSequence = true; + + if (movePromotesPiece(thunkMove)) { inJumpSequence = false; } + + board.movePiece(thunkMove); + gamePanel.movePiece(thunkMove); + + while (inJumpSequence) { + thunkMove = getThunkMove(); + + if (thunkMove != null) { + if (movePromotesPiece(thunkMove)) { + inJumpSequence = false; + } + board.movePiece(thunkMove); + gamePanel.movePiece(thunkMove); + } else { + inJumpSequence = false; + } + } + } else { + gamePanel.displayMessage("Game over. User has won!"); } } - + } + + public boolean movePromotesPiece(Move move) { + return board.getPiece(move.source).getType() != Type.KING && + board.isPromotionLocation(move.destination); + } public Move getThunkMove() { @@ -76,6 +112,64 @@ public Move getThunkMove() { return null; } } + + public Move getMinimaxMove(int depth) { + 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 board : boardFrontier) { + moveScores.add(this.getMinimaxScore(otherColor, board, depth)); + } + + int maxScore = Integer.MIN_VALUE; + Move bestMove = null; + + for (int i = 0; i < moveScores.size(); ++i) { + if (moveScores.get(i) > maxScore) { + bestMove = moveFrontier.get(i); + maxScore = moveScores.get(i); + } + System.out.println("Score[" + i + "] = " + moveScores.get(i)); + } + System.out.println("---"); + + return bestMove; + } + + public int getMinimaxScore(Color color, Board b, int depth) { + if (depth == 0 || b.getBlackPieces() == 0 || b.getWhitePieces() == 0) { + Color otherColor = color == Color.BLACK ? Color.WHITE : Color.BLACK; + return b.getHeuristic(otherColor); + } + ArrayList boardFrontier = board.generateFrontier(color); + + ArrayList moveScores = new ArrayList(); + + for (Board board : boardFrontier) { + Color nextColor = color == Color.BLACK ? Color.WHITE : Color.BLACK; + moveScores.add(getMinimaxScore(nextColor, board, depth - 1)); + } + for (int score : moveScores) { + System.out.println(score); + } + System.out.println("---"); + if (color == GameConstants.THUNK_COLOR) { + // Maximize + return Collections.max(moveScores); + } + else { + // Minimize + return Collections.min(moveScores); + } + } + + public void notifyClientWin() { + gamePanel.displayMessage("Game over. Client has won!"); + } public ArrayList getAvailableMoves(Location source) { @@ -90,6 +184,10 @@ public ArrayList getAllAvailableJumpMoves(Color player) { return board.generateAllJumpMoves(player); } + public ArrayList getAllAvailableMoves(Color player) { + return board.generateAllMoves(player); + } + public void setGamePanel(GamePanel panel) { this.gamePanel = panel; } diff --git a/src/controller/GameConstants.java b/src/controller/GameConstants.java index bb0d094..ec88811 100644 --- a/src/controller/GameConstants.java +++ b/src/controller/GameConstants.java @@ -7,4 +7,6 @@ public class GameConstants { public static final int SERVER_MODE = 1; 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; } diff --git a/src/model/Board.java b/src/model/Board.java index 0306d84..852886a 100755 --- a/src/model/Board.java +++ b/src/model/Board.java @@ -45,7 +45,9 @@ public Board(Board other) { Piece[][] other_representation = other.getRepresentation(); for (int i = 0; i < other_representation.length; ++i) { for (int j = 0; j < other_representation[0].length; ++j) { - this.representation[i][j] = new Piece(other_representation[i][j]); + if (other_representation[i][j] != null) { + this.representation[i][j] = new Piece(other_representation[i][j]); + } } } movesSinceCapture = other.getMovesSinceCapture(); @@ -100,7 +102,12 @@ public void movePiece(Move move) { /* Remove the piece being jumped ("monkey in the middle") */ representation[monkeyRow][monkeyCol] = null; + + this.movesSinceCapture = 0; } + else { + ++this.movesSinceCapture; + } /* Place the piece in the destination cell */ representation[destRow][destCol] = representation[sourceRow][sourceCol]; @@ -359,11 +366,14 @@ public boolean isOccupied(Location location) { } public boolean canPromote(Piece p) { - int row = p.getLocation().row; return p.getType() != Type.KING && - ((row == 0 && p.getColor() == Color.WHITE) || - (row == BOARD_SIZE - 1 && p.getColor() == Color.BLACK)); + isPromotionLocation(p.getLocation()); + } + + public boolean isPromotionLocation(Location location) { + return (location.row == 0 || + location.row == BOARD_SIZE - 1 ); } public int getHeuristic(Color color) { @@ -387,6 +397,14 @@ public Piece getLastPieceMoved() { } public Move getLastMove() { return this.lastMove; + } + + public int getWhitePieces() { + return this.whitePieces; + } + + public int getBlackPieces() { + return this.blackPieces; } } diff --git a/src/model/Color.java b/src/model/Color.java index f7f3553..a710e58 100755 --- a/src/model/Color.java +++ b/src/model/Color.java @@ -2,5 +2,5 @@ public enum Color { WHITE, - BLACK + BLACK, } diff --git a/src/view/GamePanel.java b/src/view/GamePanel.java index 1ed4fb0..ca32ba8 100644 --- a/src/view/GamePanel.java +++ b/src/view/GamePanel.java @@ -175,6 +175,10 @@ public void run() { canvas.highlightAndValidateSquare(jump.source); } } + + if (outOfMoves()) { + game.notifyClientWin(); + } } }).start(); } @@ -203,4 +207,8 @@ public boolean isInJumpSequence() { public boolean isForceJump() { return !game.getAllAvailableJumpMoves(GameConstants.USER_COLOR).isEmpty(); } + + public boolean outOfMoves() { + return game.getAllAvailableMoves(GameConstants.USER_COLOR).isEmpty(); + } }