From Anmol, 1 Year ago, written in Java.
Embed
  1.  
  2. public class Game {
  3.  
  4.         private Board board;
  5.         private Player pWhite;
  6.         private Player pBlack;
  7.  
  8.         Game(Player pWhite, Player pBlack) {
  9.                 // We can plug in another implementation for board if we want. e.g. ChineseChessBoard as we discussed.
  10.                 board = new ChessBoard();
  11.                 this.pWhite = pWhite;
  12.                 this.pBlack = pBlack;
  13.         }
  14.  
  15.         /* Invoked for any move made by a player.
  16.          * Input: start position, end position and the player who made the move.
  17.          * Return the winner if the game ends else returns null.
  18.          * Throws exception if invalid move.
  19.          */
  20.         Player makeMove(Position start, Position end, Player p) {
  21.  
  22.                 // validate the player making the move is one of the two playing
  23.                 if(!p.equals(pWhite) && !p.equals(pBlack)) {
  24.                         throw InvalidPlayerException("Invalid player");
  25.                 }
  26.  
  27.                 boolean isPlayerWhite = p == pWhite ? true : false;
  28.  
  29.                 // let the board figure out the rest
  30.                 board.makeMove(start, end, isPlayerWhite);
  31.  
  32.                 // check for game termination rules and determine a winner player..helper function.
  33.                 return checkGameEndAndGetWinner();
  34.         }
  35.  
  36. }
  37.  
  38. public class ChessBoard implements Board {
  39.  
  40.         private Square[][] squares;
  41.  
  42.         private final static int BOARD_HEIGHT = 8;
  43.         private final static int BOARD_WIDTH = 8;
  44.         private final static int PAWN_COUNT = 8;
  45.         private final static int BISHOP_COUNT = 2;
  46.         private final static int ROOK_COUNT = 2;
  47.         private final static int KNIGHT_COUNT = 2;
  48.         private final static int QUEEN_COUNT  =1;
  49.         private final static int KING_COUNT  =1;
  50.  
  51.         /*
  52.          * Initialize the board with both player pieces at relevant position
  53.          */
  54.         ChessBoard() {
  55.                 squares =  new Square[8][8];
  56.  
  57.                 // init pawns
  58.                 for(int i=0; i<PAWN_COUNT; i++){
  59.                         // place white pawns
  60.                         squares[0][i] = new Square(new Pawn(true), false);
  61.                         // place black pawns
  62.                         squares[7][i] = new Square(new Pawn(false), false);        
  63.                 }
  64.                 // Similarly initialize other pieces at a relevant positions
  65.                 // as well as initialize empty squares.
  66.  
  67.         }
  68.  
  69.  
  70.         /*
  71.          * Validate the move and make the move.
  72.          * Make move throws exception if the move is invalid.
  73.          */
  74.         void makeMove(Position start, Position end, boolean isWhite) {
  75.  
  76.                 // Validate the move.
  77.                 boolean isValid = isMoveValid(start, end, isWhite);
  78.                 if(!isValid) {
  79.                         throw new InvalidMoveException("Invalid Move");
  80.                 }
  81.  
  82.                 // Make the actual move if validation succeeded.
  83.                 // also need to potentiall kill/remove opposite pieces in the path ?
  84.                 squares[end.x][end.y] = squares[start.x][start.y];
  85.                 // empty the old position.
  86.                 squares[start.x][start.y] = new Square(null, true);
  87.         }
  88.  
  89.         /*
  90.          *  Validate the move. Returns boolean if the move is valid or not
  91.          *  Checks for piece level validation and also validates that no other same color piece is blocking the path traced
  92.          */
  93.         private boolean isMoveValid(Position start, Position end, boolean isWhite) {
  94.                 Piece p = board[start.x][start.y].piece;
  95.  
  96.                 //Validate piece access by the player
  97.                 if(p == null || p.isWhite != isWhite) {
  98.                         throw InvalidMoveException("No piece or player doesn't have access to the piece at position");
  99.                 }
  100.  
  101.                 // isMoveValid based on Piece rules
  102.                 boolean isMoveValid = p.isMoveValid(start, end);
  103.                 if(!p.isMoveValid(start,end)) {
  104.                         return false;
  105.                 }
  106.  
  107.                 // Get position traced excluding the start/end position of the piece
  108.                 // return move false if blocked by same color piece.
  109.                 // also need to remove opposite pieces if any
  110.                 List<Position> moveSquaresVisited =  piece.getSquaresVisited(start, end);
  111.                 for(Position pos : moveSquaresVisited) {
  112.                         if(!(board[pos.x][pos.y].isEmpty || board[pos.x][pos.y].piece.isWhite != isWhite)) {
  113.                                 return false;
  114.                         }
  115.                 }
  116.         }
  117.  
  118. }
  119.  
  120. public abstract class Piece {
  121.         boolean isWhite;
  122.  
  123.         // Validate if the move is valid for the Piece type
  124.         abstract boolean isMoveValid(Position start, Position end);
  125.  
  126.         // get the path/squares visited by the move
  127.         abstract List<Position> getSquaresVisited(Position start, Position end);
  128.  
  129. }
  130.  
  131. // An example of a piece subclass with a validateMove functionality...
  132. // There will be other subclasses like Queen, Bishop, Knight, Pawn etc.
  133. public class King extends Piece {
  134.  
  135.         public King(boolean isWhite) {
  136.                 super(isWhite);
  137.         }
  138.  
  139.         @Override
  140.         public boolean isMoveValid(Position start, Position end) {
  141.                 // One move in any direction
  142.                 if(Math.sqrt(Math.pow(start.x - end.x,2)) + Math.pow(start.y - end.y, 2) == Math.sqrt(2)) {
  143.                         return true;
  144.                 }
  145.                 return  false;
  146.         }
  147.  
  148.         public List<Position> getSquaresVisited(Position start, Position end) {
  149.                 // For king, there are no intermediate squares visited so we return an empty list here .
  150.                 return new ArrayList<Position>();
  151.         }
  152.  
  153. }
  154.  
  155. // Another example of a piece subclass with a validateMove functionality...
  156. // There will be other subclasses like Queen, Bishop, Knight, Pawn etc.
  157. public class Rook extends Piece {
  158.  
  159.  
  160.         public Rook(boolean isWhite) {
  161.                 super(isWhite);
  162.         }
  163.  
  164.         @Override
  165.         public boolean isMoveValid(Position start, Position end) {
  166.                 // a valid move maintains the same x or y position.
  167.                 if(start.x == end.x) {
  168.                         return true;
  169.                 }
  170.                 if(start.y == end.y) {
  171.                         return true;
  172.                 }
  173.                 return false;
  174.         }
  175.  
  176.         public List<Position> getSquaresVisited(Position start, Position end) {
  177.                 List<Position> intermediatePositionsVisited = new ArrayList<Position>();
  178.                 if(start.x == end.x) {
  179.                         int direction = end.y > start.y ? 1 : -1;
  180.                         for (int i = start.y+1; i <end.y; i = i + direction) {
  181.                                 intermediatePositionsVisited.add(new Position(start.x, i));
  182.                         }
  183.                 }
  184.                 else if(start.y == end.y) {
  185.                         int direction = end.x > start.x ? 1 : -1;
  186.                         for (int i = start.x+1; i <end.x; i = i + direction) {
  187.                                 intermediatePositionsVisited.add(new Position(i, start.y));
  188.                         }
  189.                 }
  190.                 return intermediatePositionsVisited;
  191.         }
  192. }
  193.  
  194. public class Square {
  195.         Piece p;
  196.         boolean isEmpty;
  197. }
  198.  
  199. public class Player {
  200.         // Player metadata
  201.         String playerId;
  202.         String playerName;
  203. }
  204.  
  205. public class Position {
  206.         int x;
  207.         int y;
  208. }