import java.awt.*; public class Board { //--------------------------------------PUBLIC FIELDS public final static int BOARD_SIZE = 8; //the number of squares per side public final static int SPACE_SIZE = 75; //number of pixels per side of a square //----------------------------------INSTANCE FIELDS private Space[][] board; //holds the game data private boolean turn; //determines whose turn it is private int playerOnePieces; //number of remaining pieces belonging to player one private int playerTwoPieces; //number of remaining pieces belonging to player two private boolean mustJump; //used in determining whether a player is executing multiple jumps private int jumpRow; //tracks the row of the piece executing multiple jumps private int jumpColumn; //tracks the column of the piece executing multiple jumps private String playerOneName; //the first player's name private String playerTwoName; //the second player's name //---------------------------------INITIALIZATION/CONSTRUCTOR FUNCTIONS //the default constructor public Board(String playerOneName_, String playerTwoName_) { playerOneName = playerOneName_; playerTwoName = playerTwoName_; turn = Piece.PLAYER_ONE; playerOnePieces = 0; playerTwoPieces = 0; initializeBoard(); setUpPieces(); } //creates spaces public void initializeBoard() { board = new Space[BOARD_SIZE][BOARD_SIZE]; for(int i = 0; i < BOARD_SIZE; i++) { for(int j = 0; j < BOARD_SIZE; j++) { board[i][j] = new Space(); } } } //sets up starting game position public void setUpPieces() { int offSet = 0; for(int i = 0; i < 3; i++) { if(offSet == 1) { offSet = 0; } else { offSet = 1; } for(int j = offSet; j < BOARD_SIZE; j += 2) { board[i][j].setPiece(new Piece(Piece.PLAYER_TWO)); playerTwoPieces++; //first player offset is opposite second player offset if(offSet == 0) { board[i + 5][j + 1].setPiece(new Piece(Piece.PLAYER_ONE)); playerOnePieces++; } else { board[i + 5][j - 1].setPiece(new Piece(Piece.PLAYER_ONE)); playerOnePieces++; } } } } //-----------------------------------------------------MAIN METHODS //the draw method public void draw(Graphics2D g2) { boolean red = false; for(int i = 0; i < BOARD_SIZE; i++) { for(int j = 0; j < BOARD_SIZE; j++) { red = !red; g2.setColor(Color.black); if(red) g2.setColor(Color.red); //spaces do not draw themselves but pieces do g2.fill(new Rectangle(j * SPACE_SIZE, i * SPACE_SIZE, SPACE_SIZE, SPACE_SIZE)); if(board[i][j].isOccupied()) { board[i][j].draw(g2, j * SPACE_SIZE, i * SPACE_SIZE); } } red = !red; } } //returns the current turn public boolean getTurn() { return turn; } public void killGame() { playerOnePieces = 0; playerTwoPieces = 0; initializeBoard(); } //calculates the legality of a move and performs it public boolean move(int fromRow, int fromColumn, int toRow, int toColumn) { //game is already over if(gameOver()) return false; //coordinates are illegal if(fromRow >= Board.BOARD_SIZE || fromColumn >= Board.BOARD_SIZE || toRow >= Board.BOARD_SIZE || toColumn >= Board.BOARD_SIZE || fromRow < 0 || fromColumn < 0 || toRow < 0 || toColumn < 0) return false; //cannot move because space is empty if(!board[fromRow][fromColumn].isOccupied()) return false; //not the same player if(board[fromRow][fromColumn].getPiece().isWhite() != turn) return false; //destination is occupied if(board[toRow][toColumn].isOccupied()) return false; //illegal destination - move is not diagonal if(Math.abs(fromColumn - toColumn) != Math.abs(fromRow - toRow)) return false; //illegal destination - move is too far if(Math.abs(fromColumn - toColumn) > 2 || Math.abs(fromRow - toRow) > 2) return false; //illegal destination - wrong direction (player one) if(!board[fromRow][fromColumn].getPiece().isKing() && turn == Piece.PLAYER_ONE && !(fromRow - toRow > 0)) return false; //illegal destination - wrong direction (player two) if(!board[fromRow][fromColumn].getPiece().isKing() && turn == Piece.PLAYER_TWO && !(fromRow - toRow < 0)) return false; //not following through on multiple jumps if(mustJump && (fromRow != jumpRow || fromColumn != jumpColumn) && !checkJump(fromRow, fromColumn, toRow, toColumn)) return false; //jumping boolean didJump = false; if((Math.abs(fromColumn - toColumn) == 2)) { if(!jump(fromRow, fromColumn, toRow, toColumn)) { return false; } else { didJump = true; } } //move was successful //king if((turn == Piece.PLAYER_ONE && toRow == 0) || (turn == Piece.PLAYER_TWO && toRow == Board.BOARD_SIZE - 1)) board[fromRow][fromColumn].getPiece().setKing(); //move the actual piece board[toRow][toColumn].setPiece(board[fromRow][fromColumn].popPiece()); //check for multiple jumps, otherwise other player's turn if(didJump) { if(!canJump(toRow, toColumn)) { mustJump = false; turn = !turn; } else { mustJump = true; jumpRow = toRow; jumpColumn = toColumn; } } else { turn = !turn; } return true; } //jumping over another piece private boolean jump(int fromRow, int fromColumn, int toRow, int toColumn) { int columnDirection = 0, rowDirection = 0; if(turn == Piece.PLAYER_ONE) rowDirection = -1; if(turn == Piece.PLAYER_TWO) rowDirection = 1; if(board[fromRow][fromColumn].getPiece().isKing()) { if(fromRow - toRow < 0) rowDirection = 1; if(fromRow - toRow > 0) rowDirection = -1; } if(fromColumn - toColumn < 0) columnDirection = 1; if(fromColumn - toColumn > 0) columnDirection = -1; //illegal move - trying to jump empty space if(!board[fromRow + rowDirection][fromColumn + columnDirection].isOccupied()) return false; //illegal move - trying to capture own piece if(board[fromRow + rowDirection][fromColumn + columnDirection].getPiece().isWhite() == turn) return false; //jump was successful board[fromRow + rowDirection][fromColumn + columnDirection].popPiece(); if(turn == Piece.PLAYER_ONE) playerTwoPieces--; if(turn == Piece.PLAYER_TWO) playerOnePieces--; return true; } //used for deciding if multiple jumps are possible private boolean canJump(int row, int column) { for(int i = -2; i <= 2; i ++) { for(int j = -2; j <= 2; j++) { if(isLegalMove(row, column, row + i, column + j)) { if(checkJump(row, column, row + i, column + j)) { return true; } } } } return false; } //returns the game state public boolean gameOver() { return playerOnePieces == 0 || playerTwoPieces == 0; } //returns the game state in string form public String getMessage() { if(playerOnePieces == 0) return "Game Over! " + playerTwoName + " won!"; if(playerTwoPieces == 0) return "Game Over! " + playerOneName + " won!"; String versus = playerOneName + " vs. " + playerTwoName; if(turn == Piece.PLAYER_ONE) { versus = ">>" + versus; } else { versus += "<<"; } return versus; } //----------------------------------------AI INTERFACE FUNCTIONS //returns an matrix representing the current board state public int[][] getAIBoard() { int ret[][] = new int[BOARD_SIZE][BOARD_SIZE]; for(int i = 0; i < BOARD_SIZE; i++) { for(int j = 0; j < BOARD_SIZE; j++) { Piece p = board[i][j].getPiece(); if(p == null) { ret[i][j] = CheckersAI.EMPTY_SPACE; } else { if(p.isWhite()) ret[i][j] = CheckersAI.WHITE_PIECE; if(p.isWhite() && p.isKing()) ret[i][j] = CheckersAI.WHITE_KING; if(!p.isWhite()) ret[i][j] = CheckersAI.BLACK_PIECE; if(!p.isWhite() && p.isKing()) ret[i][j] = CheckersAI.BLACK_KING; } } } return ret; } //similar to the move function sans the actual moving public boolean isLegalMove(int fromRow, int fromColumn, int toRow, int toColumn) { //game is already over if(gameOver()) return false; //coordinates are illegal if(fromRow >= Board.BOARD_SIZE || fromColumn >= Board.BOARD_SIZE || toRow >= Board.BOARD_SIZE || toColumn >= Board.BOARD_SIZE || fromRow < 0 || fromColumn < 0 || toRow < 0 || toColumn < 0) return false; //cannot move because space is empty if(!board[fromRow][fromColumn].isOccupied()) return false; //not the same player if(board[fromRow][fromColumn].getPiece().isWhite() != turn) return false; //destination is occupied if(board[toRow][toColumn].isOccupied()) return false; //illegal destination - move is not diagonal if(Math.abs(fromColumn - toColumn) != Math.abs(fromRow - toRow)) return false; //illegal destination - move is too far if(Math.abs(fromColumn - toColumn) > 2 || Math.abs(fromRow - toRow) > 2) return false; //illegal destination - wrong direction (player one) if(!board[fromRow][fromColumn].getPiece().isKing() && turn == Piece.PLAYER_ONE && !(fromRow - toRow > 0)) return false; //illegal destination - wrong direction (player two) if(!board[fromRow][fromColumn].getPiece().isKing() && turn == Piece.PLAYER_TWO && !(fromRow - toRow < 0)) return false; //illegal jump attempt if((Math.abs(fromColumn - toColumn) == 2) && !checkJump(fromRow, fromColumn, toRow, toColumn)) return false; //not following through on multiple jumps if(mustJump && (fromRow != jumpRow || fromColumn != jumpColumn) && !checkJump(fromRow, fromColumn, toRow, toColumn)) return false; //move is legal return true; } //similar to the jump method without actually performing the jump public boolean checkJump(int fromRow, int fromColumn, int toRow, int toColumn) { //coordinates are illegal if(fromRow >= Board.BOARD_SIZE || fromColumn >= Board.BOARD_SIZE || toRow >= Board.BOARD_SIZE || toColumn >= Board.BOARD_SIZE || fromRow < 0 || fromColumn < 0 || toRow < 0 || toColumn < 0) return false; int columnDirection = 0, rowDirection = 0; if(turn == Piece.PLAYER_ONE) rowDirection = -1; if(turn == Piece.PLAYER_TWO) rowDirection = 1; if(board[fromRow][fromColumn].getPiece().isKing()) { if(fromRow - toRow < 0) rowDirection = 1; if(fromRow - toRow > 0) rowDirection = -1; } if(fromColumn - toColumn < 0) columnDirection = 1; if(fromColumn - toColumn > 0) columnDirection = -1; //illegal move - trying to jump empty space if(!board[fromRow + rowDirection][fromColumn + columnDirection].isOccupied()) return false; //illegal move - trying to capture own piece if(board[fromRow + rowDirection][fromColumn + columnDirection].getPiece().isWhite() == turn) return false; //jump is legal return true; } }