diff --git a/src/controller/CheckersMain.java b/src/controller/CheckersMain.java index 461139d..ddb9741 100644 --- a/src/controller/CheckersMain.java +++ b/src/controller/CheckersMain.java @@ -6,6 +6,9 @@ import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import model.Board; +import player.ComputerPlayer; +import player.HumanPlayer; +import player.ServerPlayer; import view.CheckersWindow; public class CheckersMain { @@ -41,19 +44,35 @@ public class CheckersMain { catch (IllegalAccessException e) { // handle exception } - + Board board = new Board(); final Game game = new Game(board); + ComputerPlayer computer = new ComputerPlayer(GameConstants.THUNK_COLOR, board); + final HumanPlayer user = new HumanPlayer(GameConstants.USER_COLOR, board, game); + + game.setComputer(computer); + if (mode == GameConstants.SERVER_MODE) { - /* Create a ServerListener to listen for messages from the server */ + final ServerPlayer server = new ServerPlayer(GameConstants.SERVER_COLOR, board, game); + game.setOpponent(server); + new Thread(new Runnable() { + + @Override + public void run() { + server.listen(); + } + + }).start(); + } else { + game.setOpponent(user); } SwingUtilities.invokeLater(new Runnable() { @Override public void run() { - CheckersWindow window = new CheckersWindow(game, mode); + CheckersWindow window = new CheckersWindow(game, user, mode); window.open(); } }); diff --git a/src/controller/Game.java b/src/controller/Game.java index 0f7de66..921c3b9 100755 --- a/src/controller/Game.java +++ b/src/controller/Game.java @@ -9,258 +9,75 @@ import model.Color; import model.Location; import model.Move; import model.Type; +import player.ComputerPlayer; +import player.HumanPlayer; +import player.Player; import view.GamePanel; public class Game { + private ComputerPlayer computer; + private Player opponent; private Board board; private GamePanel gamePanel; - private boolean inJumpSequence; - public Game(Board board) { this.board = board; - this.inJumpSequence = false; } /* 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 - } - - /* If the piece that jumped has no more jumps */ - if (move.isJump() && getAvailableMoves(move.destination).isEmpty()) - inJumpSequence = false; - + checkEndGame(); + } + + public Move makeComputerMove() { /* If the game is not in the middle of a jump sequence, move the thunk */ - if (!inJumpSequence) { - - Move thunkMove = getMinimaxMove(GameConstants.MAX_SEARCH_DEPTH, inJumpSequence); - if (thunkMove != null) { - if (thunkMove.isJump()) inJumpSequence = true; - - if (movePromotesPiece(thunkMove)) { - inJumpSequence = false; - } - - board.movePiece(thunkMove); - gamePanel.movePiece(thunkMove); - - while (inJumpSequence) { - thunkMove = getMinimaxMove(GameConstants.MAX_SEARCH_DEPTH, inJumpSequence); + Move computerMove = null; + + if (!opponent.isInJumpSequence()) { - if (thunkMove != null) { - if (movePromotesPiece(thunkMove)) { - inJumpSequence = false; - } - board.movePiece(thunkMove); - gamePanel.movePiece(thunkMove); - } else { - inJumpSequence = false; - } - } - } else { + computerMove = computer.getMove(); + if (computerMove == null) { gamePanel.displayMessage("Game over. User has won!"); + gamePanel.disableInteraction(); + } else { + board.movePiece(computerMove); + gamePanel.movePiece(computerMove); } } - } - - private boolean movePromotesPiece(Move move) { - return board.getPiece(move.source).getType() != Type.KING && - board.isPromotionLocation(move.destination); - } - - private Move getThunkMove() { - ArrayList availableMoves; - - if (inJumpSequence) { - availableMoves = - board.generateJumpMovesForPiece(board.getLastPieceMoved()); - } else { - availableMoves = board.generateAllMoves(GameConstants.THUNK_COLOR); - } - - if (!availableMoves.isEmpty()) { - /* Just take the first move we see */ - Move moveChoice = availableMoves.get(0); - return moveChoice; - } else { - return null; - } - } - - private Move getMinimaxMove(int depth, boolean inJumpSequence) { - ArrayList boardFrontier = null; - ArrayList moveFrontier = null; - ArrayList moveScores = new ArrayList(); - - if (inJumpSequence) { - /* Generate the frontier only for the piece that just moves */ - boardFrontier = board.generateJumpFrontierForPiece(board.getLastPieceMoved()); - moveFrontier = board.generateJumpMovesForPiece(board.getLastPieceMoved()); - - /* If we can't jump anymore, we can't make a move */ - if (boardFrontier.isEmpty()) { - return null; - } - - } else { - /* Generate the frontier for all pieces */ - boardFrontier = board.generateFrontier(GameConstants.THUNK_COLOR); - moveFrontier = board.generateAllMoves(GameConstants.THUNK_COLOR); - } - - Color nextColor; - /* Determine the next color to move */ - if (inJumpSequence) { - nextColor = GameConstants.THUNK_COLOR; - } else if (GameConstants.THUNK_COLOR == Color.BLACK) { - 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); - } - - System.out.println(moveFrontier.get(i) + " --> " + moveScores.get(i)); - } - /* All moves have the same outcome */ - if (!moveScores.isEmpty() && maxScore == Collections.min(moveScores)) { - return getBestOfSimilarMoves(moveFrontier); - } - System.out.println("Choosing: " + bestMove); - - return bestMove; - } - - private int getMinimaxScore(Color color, Board b, int depth, boolean inJumpSequence) { - ArrayList boardFrontier; - ArrayList moveScores = new ArrayList(); - Color otherColor = (color == Color.BLACK ? Color.WHITE : Color.BLACK); - - if (depth == 0) { - return b.getHeuristic(otherColor); - } - - if (inJumpSequence) { - /* Generate the frontier only for the piece that just moved */ - boardFrontier = b.generateJumpFrontierForPiece(b.getLastPieceMoved()); - - /* If we can't jump anymore, get out of the jump sequence */ - if (boardFrontier.isEmpty()) { - return getMinimaxScore(otherColor, b, depth-1, inJumpSequence); - } - } else { - /* Generate the frontier for all pieces */ - boardFrontier = b.generateFrontier(color); - } - - /* If we have reached the maximum depth or an end state for the game */ - if (b.getBlackPieces() == 0 || b.getWhitePieces() == 0 - || boardFrontier.size() == 0) { - return b.getHeuristic(otherColor); - } - - Color nextColor; - /* Determine the next color to move */ - if (inJumpSequence) { - nextColor = color; - } else { - nextColor = otherColor; - } - - for (Board board : boardFrontier) { - int moveScore = getMinimaxScore(nextColor, board, depth - 1, inJumpSequence); - moveScores.add(moveScore); - } - - if (color == GameConstants.THUNK_COLOR) { - // Maximize - return Collections.max(moveScores); - } - else { - // Minimize - return Collections.min(moveScores); - } - + return computerMove; } - private Move getBestOfSimilarMoves(ArrayList moves) { - ArrayList regularMoves = new ArrayList(); - - for (Move move : moves) { - if (!move.isJump()) { - regularMoves.add(move); - } - } - - /* We prefer to advance regular checkers over kings - * if all moves have the same outcome - */ - if (!regularMoves.isEmpty()) { - return regularMoves.get(ThreadLocalRandom.current().nextInt(regularMoves.size())); + public void checkEndGame() { + if (board.getMovesSinceCapture() > GameConstants.MAX_PASSIVE_MOVES) { + gamePanel.displayMessage("It's a tie! Be more aggressive next time."); + gamePanel.disableInteraction(); } - - return moves.get(ThreadLocalRandom.current().nextInt(moves.size())); } public void notifyClientWin() { gamePanel.displayMessage("Game over. Client has won!"); } - - public ArrayList getAvailableMoves(Location source) { - if (inJumpSequence) { - return board.generateJumpMovesForPiece(board.getPiece(source)); - } else { - return board.generateMovesForPiece(board.getPiece(source)); - } - } - - public ArrayList getAllAvailableJumpMoves(Color player) { - return board.generateAllJumpMoves(player); + public void setGamePanel(GamePanel panel) { + this.gamePanel = panel; } - public ArrayList getAllAvailableMoves(Color player) { - return board.generateAllMoves(player); + public void setComputer(ComputerPlayer computer) { + this.computer = computer; } - - public void setGamePanel(GamePanel panel) { - this.gamePanel = panel; + + public void setOpponent(Player opponent) { + this.opponent = opponent; } - public boolean isInJumpSequence() { - return inJumpSequence; + public Player getComputer() { + return computer; } + + } diff --git a/src/controller/GameConstants.java b/src/controller/GameConstants.java index 7cc7669..654b549 100644 --- a/src/controller/GameConstants.java +++ b/src/controller/GameConstants.java @@ -5,10 +5,11 @@ import model.Color; public class GameConstants { public static final int USER_MODE = 0; 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 Color THUNK_COLOR = Color.WHITE; + public static Color USER_COLOR = Color.BLACK; + public static Color SERVER_COLOR = Color.BLACK; public static final int MAX_PASSIVE_MOVES = 50; - public static final int MAX_SEARCH_DEPTH = 7; + public static final int MAX_SEARCH_DEPTH = 6; public static final int BOARD_SIZE = 8; /* Parameters to the heuristic */ diff --git a/src/model/Board.java b/src/model/Board.java index cf6b3e9..c9fe897 100755 --- a/src/model/Board.java +++ b/src/model/Board.java @@ -384,6 +384,11 @@ public class Board { isPromotionLocation(p.getLocation()); } + public boolean movePromotesPiece(Move move) { + return getPiece(move.source).getType() != Type.KING && + isPromotionLocation(move.destination); + } + public boolean isPromotionLocation(Location location) { return (location.row == 0 || location.row == BOARD_SIZE - 1 ); diff --git a/src/player/ComputerPlayer.java b/src/player/ComputerPlayer.java new file mode 100644 index 0000000..9f82b94 --- /dev/null +++ b/src/player/ComputerPlayer.java @@ -0,0 +1,162 @@ +package player; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.concurrent.ThreadLocalRandom; + +import controller.GameConstants; +import model.Board; +import model.Color; +import model.Location; +import model.Move; + +public class ComputerPlayer extends Player { + + public ComputerPlayer(Color color, Board board) { + super(color, board); + } + + public Move getMove() { + Move move = getMinimaxMove(GameConstants.MAX_SEARCH_DEPTH, inJumpSequence); + if (move == null) { + inJumpSequence = false; + }else if (board.movePromotesPiece(move)) { + inJumpSequence = false; + } + return move; + } + + private Move getMinimaxMove(int depth, boolean inJumpSequence) { + ArrayList boardFrontier = null; + ArrayList moveFrontier = null; + ArrayList moveScores = new ArrayList(); + + if (inJumpSequence) { + /* Generate the frontier only for the piece that just moves */ + boardFrontier = board.generateJumpFrontierForPiece(board.getLastPieceMoved()); + moveFrontier = board.generateJumpMovesForPiece(board.getLastPieceMoved()); + + /* If we can't jump anymore, we can't make a move */ + if (boardFrontier.isEmpty()) { + return null; + } + + } else { + /* Generate the frontier for all pieces */ + boardFrontier = board.generateFrontier(GameConstants.THUNK_COLOR); + moveFrontier = board.generateAllMoves(GameConstants.THUNK_COLOR); + } + + Color nextColor; + /* Determine the next color to move */ + if (inJumpSequence) { + nextColor = GameConstants.THUNK_COLOR; + } else if (GameConstants.THUNK_COLOR == Color.BLACK) { + 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); + } + + System.out.println(moveFrontier.get(i) + " --> " + moveScores.get(i)); + } + + /* All moves have the same outcome */ + if (!moveScores.isEmpty() && maxScore == Collections.min(moveScores)) { + return getBestOfSimilarMoves(moveFrontier); + } + System.out.println("Choosing: " + bestMove); + + return bestMove; + } + + private int getMinimaxScore(Color color, Board b, int depth, boolean inJumpSequence) { + ArrayList boardFrontier; + ArrayList moveScores = new ArrayList(); + Color otherColor = (color == Color.BLACK ? Color.WHITE : Color.BLACK); + + if (depth == 0) { + return b.getHeuristic(otherColor); + } + + if (inJumpSequence) { + /* Generate the frontier only for the piece that just moved */ + boardFrontier = b.generateJumpFrontierForPiece(b.getLastPieceMoved()); + + /* If we can't jump anymore, get out of the jump sequence */ + if (boardFrontier.isEmpty()) { + return getMinimaxScore(otherColor, b, depth-1, inJumpSequence); + } + } else { + /* Generate the frontier for all pieces */ + boardFrontier = b.generateFrontier(color); + } + + /* If we have reached the maximum depth or an end state for the game */ + if (b.getBlackPieces() == 0 || b.getWhitePieces() == 0 + || boardFrontier.size() == 0) { + return b.getHeuristic(otherColor); + } + + Color nextColor; + /* Determine the next color to move */ + if (inJumpSequence) { + nextColor = color; + } else { + nextColor = otherColor; + } + + for (Board board : boardFrontier) { + int moveScore = getMinimaxScore(nextColor, board, depth - 1, inJumpSequence); + moveScores.add(moveScore); + } + + if (color == GameConstants.THUNK_COLOR) { + // Maximize + return Collections.max(moveScores); + } + else { + // Minimize + return Collections.min(moveScores); + } + + } + + private Move getBestOfSimilarMoves(ArrayList moves) { + ArrayList regularMoves = new ArrayList(); + + for (Move move : moves) { + if (!move.isJump()) { + regularMoves.add(move); + } + } + + /* We prefer to advance regular checkers over kings + * if all moves have the same outcome + */ + if (!regularMoves.isEmpty()) { + return regularMoves.get(ThreadLocalRandom.current().nextInt(regularMoves.size())); + } + + return moves.get(ThreadLocalRandom.current().nextInt(moves.size())); + } + + + +} diff --git a/src/player/HumanPlayer.java b/src/player/HumanPlayer.java new file mode 100644 index 0000000..db357c0 --- /dev/null +++ b/src/player/HumanPlayer.java @@ -0,0 +1,41 @@ +package player; + +import controller.Game; +import model.Board; +import model.Color; +import model.Move; + +public class HumanPlayer extends Player { + private Game game; + + public HumanPlayer(Color color, Board board, Game game) { + super(color, board); + this.game = game; + } + + public void makeMove(Move move) { + /* If this is the first jump of the jump sequence */ + if (move.isJump() && !inJumpSequence) { + inJumpSequence = true; + } + + if (board.movePromotesPiece(move)) { + inJumpSequence = false; + } + + /* Request to move the piece */ + game.requestMove(move); + + if(getAvailableMoves(move.destination).isEmpty()) { + inJumpSequence = false; + } + + /* Make the computer move */ + game.makeComputerMove(); + + /* While the computer can still move, ask it to move */ + while (game.getComputer().isInJumpSequence()) { + game.makeComputerMove(); + } + } +} diff --git a/src/player/Player.java b/src/player/Player.java new file mode 100644 index 0000000..ff70e8b --- /dev/null +++ b/src/player/Player.java @@ -0,0 +1,40 @@ +package player; + +import java.util.ArrayList; + +import model.Board; +import model.Color; +import model.Location; +import model.Move; + +public class Player { + protected Color color; + protected Board board; + protected boolean inJumpSequence; + + public Player(Color color, Board board) { + this.color = color; + this.board = board; + this.inJumpSequence = false; + } + + public boolean isInJumpSequence() { + return inJumpSequence; + } + + public ArrayList getAllAvailableMoves() { + return board.generateAllMoves(color); + } + + public ArrayList getAllAvailableJumpMoves() { + return board.generateAllJumpMoves(color); + } + + public ArrayList getAvailableMoves(Location source) { + if (inJumpSequence) { + return board.generateJumpMovesForPiece(board.getPiece(source)); + } else { + return board.generateMovesForPiece(board.getPiece(source)); + } + } +} diff --git a/src/player/ServerPlayer.java b/src/player/ServerPlayer.java new file mode 100644 index 0000000..438c5d9 --- /dev/null +++ b/src/player/ServerPlayer.java @@ -0,0 +1,85 @@ +package player; + +import java.util.ArrayList; + +import controller.Game; +import model.Board; +import model.Color; +import model.Move; + +public class ServerPlayer extends Player { + private Game game; + + public ServerPlayer(Color color, Board board, Game game) { + super(color, board); + this.game = game; + } + + public ArrayList makeMove(Move move) { + /* If this is the first jump of the jump sequence */ + if (move.isJump() && !inJumpSequence) { + inJumpSequence = true; + } + + if (board.movePromotesPiece(move)) { + inJumpSequence = false; + } + + /* Request to move the piece */ + game.requestMove(move); + + if(getAvailableMoves(move.destination).isEmpty()) { + inJumpSequence = false; + } + + ArrayList computerMoves = new ArrayList(); + + /* Make the computer move */ + Move computerMove = game.makeComputerMove(); + + if (move != null) { + computerMoves.add(computerMove); + } + + /* While the computer can still move, ask it to move */ + while (game.getComputer().isInJumpSequence()) { + computerMove = game.makeComputerMove(); + if (move != null) { + computerMoves.add(computerMove); + } + } + + /* Return the list of moves made by the computer */ + return computerMoves; + } + + public void listen() { + /* Test code */ + while(true) { + System.out.println("Listening"); + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + /* Listen to server and wait for incoming messages. + * and GameConstants.SERVER_COLOR according to who the server says + * will go first. + */ + + /* Busy-wait on moves sent from the server. When receiving a move + * message, call the static Communication.stringToMove() method. + * This will return an ArrayList of moves the server wishes to make. + * For each move, call the makeMove() method. This method will return + * the sequence of moves made by the computer in response to the + * server's move. However, in the case where the server is + * making a sequence of moves, only the last call to makeMove will + * return something meaningful. That last call will return an + * ArrayList of moves made by the computer. Call the + * Communication.moveToString() static method on this list to get + * the string to send to the server; + */ + } +} diff --git a/src/test/GameTest.java b/src/test/GameTest.java index 263c0f8..a707439 100644 --- a/src/test/GameTest.java +++ b/src/test/GameTest.java @@ -7,6 +7,8 @@ import javax.swing.UnsupportedLookAndFeelException; import controller.Game; import controller.GameConstants; import model.Board; +import player.ComputerPlayer; +import player.HumanPlayer; import view.CheckersWindow; public class GameTest { @@ -32,13 +34,18 @@ public class GameTest { // handle exception } Board board = new Board(); - final Game game = new Game(board); + ComputerPlayer computer = new ComputerPlayer(GameConstants.THUNK_COLOR, board); + final HumanPlayer user = new HumanPlayer(GameConstants.USER_COLOR, board, game); + + game.setComputer(computer); + game.setOpponent(user); + SwingUtilities.invokeLater(new Runnable() { @Override public void run() { - CheckersWindow window = new CheckersWindow(game, GameConstants.USER_MODE); + CheckersWindow window = new CheckersWindow(game, user, GameConstants.USER_MODE); window.open(); } }); diff --git a/src/view/CheckersWindow.java b/src/view/CheckersWindow.java index d808bb2..cf4e529 100644 --- a/src/view/CheckersWindow.java +++ b/src/view/CheckersWindow.java @@ -9,6 +9,7 @@ import javax.swing.JMenuItem; import controller.Game; import controller.GameConstants; +import player.HumanPlayer; /** * Represents the JFrame window that will hold the graphical components @@ -35,7 +36,7 @@ public class CheckersWindow extends JFrame { private GameEventListener gameListener; - public CheckersWindow(Game game, int mode) { + public CheckersWindow(Game game, HumanPlayer user, int mode) { super("Checkers"); this.setSize(WIDTH, HEIGHT); this.setDefaultCloseOperation(EXIT_ON_CLOSE); @@ -45,7 +46,7 @@ public class CheckersWindow extends JFrame { /* MUST be done in this order */ this.initGameListener(); this.createMenuBar(); - this.initGamePanel(game, mode); + this.initGamePanel(game, user, mode); this.pack(); } @@ -100,8 +101,8 @@ public class CheckersWindow extends JFrame { /** * Initializes the {@link GamePanel} instance */ - private void initGamePanel(Game game, int mode) { - this.gamePanel = new GamePanel(game, gameListener); + private void initGamePanel(Game game, HumanPlayer user, int mode) { + this.gamePanel = new GamePanel(game, user, gameListener); if (mode == GameConstants.SERVER_MODE) { gamePanel.disableInteraction(); } else { diff --git a/src/view/GamePanel.java b/src/view/GamePanel.java index 37f8d18..88d4686 100644 --- a/src/view/GamePanel.java +++ b/src/view/GamePanel.java @@ -12,6 +12,7 @@ import controller.GameConstants; import model.Color; import model.Location; import model.Move; +import player.HumanPlayer; /** @@ -24,6 +25,7 @@ import model.Move; public class GamePanel extends JPanel { private Game game; + private HumanPlayer user; private JLabel messageBar; private CheckersCanvas canvas; @@ -35,10 +37,11 @@ public class GamePanel extends JPanel { private boolean interactionEnabled; - public GamePanel(Game game, GameEventListener gameListener) { + public GamePanel(Game game, HumanPlayer user, GameEventListener gameListener) { super(new GridBagLayout()); this.game = game; + this.user = user; /* Initialize the layout manager */ this.layoutConstraints = new GridBagConstraints(); @@ -111,7 +114,7 @@ public class GamePanel extends JPanel { } public void highlightValidDestinations(Location source) { - ArrayList availMoves = game.getAvailableMoves(source); + ArrayList availMoves = user.getAvailableMoves(source); for (Move move : availMoves) { canvas.highlightAndValidateSquare(move.destination); @@ -154,14 +157,14 @@ public class GamePanel extends JPanel { /* Disable all user interaction before moving */ disableInteraction(); - /* Request the move */ - game.requestMove(move); + /* Make the move */ + user.makeMove(move); enableInteraction(); /* If the user just jumped and the game is still in a jump sequence */ /* Select the same piece again */ - if (move.isJump() && game.isInJumpSequence()) { + if (move.isJump() && user.isInJumpSequence()) { moveDestination.setSelected(true); highlightValidDestinations(moveDestination.getCellLocation()); moveSource = moveDestination; @@ -173,7 +176,7 @@ public class GamePanel extends JPanel { /* See if any jump moves are available */ ArrayList jumpMoves = - game.getAllAvailableJumpMoves(GameConstants.USER_COLOR); + user.getAllAvailableJumpMoves(); if (!jumpMoves.isEmpty()) { for (Move jump : jumpMoves) { @@ -204,17 +207,16 @@ public class GamePanel extends JPanel { square.getPieceColor() == Color.BLACK)); } - public boolean isInJumpSequence() { - return game.isInJumpSequence(); + return user.isInJumpSequence(); } public boolean isForceJump() { - return !game.getAllAvailableJumpMoves(GameConstants.USER_COLOR).isEmpty(); + return !user.getAllAvailableJumpMoves().isEmpty(); } public boolean outOfMoves() { - return game.getAllAvailableMoves(GameConstants.USER_COLOR).isEmpty(); + return user.getAllAvailableMoves().isEmpty(); } public void disableInteraction() {