Problem Statement: The problem is to design a Chess Game using Object Oriented Principles.
Asked In: Adobe, Amazon, Microsoft, etc.
Solution:
These type of questions are asked in interviews to Judge the Object-Oriented Design skill of a candidate. So, first of all we should think about the classes.
The main classes will be:
- Spot: A spot represents one block of the 8×8 grid and an optional piece.
- Piece: The basic building block of the system, every piece will be placed on a spot. Piece class is an abstract class. The extended classes (Pawn, King, Queen, Rook, Knight, Bishop) implements the abstracted operations.
- Board: Board is an 8×8 set of boxes containing all active chess pieces.
- Player: Player class represents one of the participants playing the game.
- Move: Represents a game move, containing the starting and ending spot. The Move class will also keep track of the player who made the move.
- Game: This class controls the flow of a game. It keeps track of all the game moves, which player has the current turn, and the final result of the game.
Let’s look at the details. These codes are self-explanatory. You can have a look at the properties/variables and methods of different classes.
Spot: To represent a cell on the chess board:
public class Spot { Â Â Â Â private Piece piece; Â Â Â Â private int x; Â Â Â Â private int y; Â Â Â Â Â Â public Spot( int x, int y, Piece piece) Â Â Â Â { Â Â Â Â Â Â Â Â this .setPiece(piece); Â Â Â Â Â Â Â Â this .setX(x); Â Â Â Â Â Â Â Â this .setY(y); Â Â Â Â } Â Â Â Â Â Â public Piece getPiece() Â Â Â Â { Â Â Â Â Â Â Â Â return this .piece; Â Â Â Â } Â Â Â Â Â Â public void setPiece(Piece p) Â Â Â Â { Â Â Â Â Â Â Â Â this .piece = p; Â Â Â Â } Â Â Â Â Â Â public int getX() Â Â Â Â { Â Â Â Â Â Â Â Â return this .x; Â Â Â Â } Â Â Â Â Â Â public void setX( int x) Â Â Â Â { Â Â Â Â Â Â Â Â this .x = x; Â Â Â Â } Â Â Â Â Â Â public int getY() Â Â Â Â { Â Â Â Â Â Â Â Â return this .y; Â Â Â Â } Â Â Â Â Â Â public void setY( int y) Â Â Â Â { Â Â Â Â Â Â Â Â this .y = y; Â Â Â Â } } |
Piece: An abstract class to represent common functionality of all chess pieces:
public abstract class Piece {       private boolean killed = false ;     private boolean white = false ;       public Piece( boolean white)     {         this .setWhite(white);     }       public boolean isWhite()     {         return this .white;     }       public void setWhite( boolean white)     {         this .white = white;     }       public boolean isKilled()     {         return this .killed;     }       public void setKilled( boolean killed)     {         this .killed = killed;     }       public abstract boolean canMove(Board board,                                  Spot start, Spot end); } |
King: To represent King as a chess piece:
public class King extends Piece {     private boolean castlingDone = false ;       public King( boolean white)     {         super (white);     }       public boolean isCastlingDone()     {         return this .castlingDone;     }       public void setCastlingDone( boolean castlingDone)     {         this .castlingDone = castlingDone;     }       @Override     public boolean canMove(Board board, Spot start, Spot end)     {         // we can't move the piece to a Spot that         // has a piece of the same color         if (end.getPiece().isWhite() == this .isWhite()) {             return false ;         }           int x = Math.abs(start.getX() - end.getX());         int y = Math.abs(start.getY() - end.getY());         if (x + y == 1 ) {             // check if this move will not result in the king             // being attacked if so return true             return true ;         }           return this .isValidCastling(board, start, end);     }       private boolean isValidCastling(Board board,                                      Spot start, Spot end)     {           if ( this .isCastlingDone()) {             return false ;         }           // Logic for returning true or false     }       public boolean isCastlingMove(Spot start, Spot end)     {         // check if the starting and         // ending position are correct     } } |
Knight: To represent Knight as a chess piece
public class Knight extends Piece {     public Knight( boolean white)     {         super (white);     }       @Override     public boolean canMove(Board board, Spot start,                                             Spot end)     {         // we can't move the piece to a spot that has         // a piece of the same colour         if (end.getPiece().isWhite() == this .isWhite()) {             return false ;         }           int x = Math.abs(start.getX() - end.getX());         int y = Math.abs(start.getY() - end.getY());         return x * y == 2 ;     } } |
Similarly, we can create classes for other pieces like Queen, Pawns, Rooks, Bishops etc.
Board: To represent a chess board:
public class Board {     Spot[][] boxes;       public Board()     {         this .resetBoard();     }       public Spot getBox( int x, int y)     {           if (x < 0 || x > 7 || y < 0 || y > 7 ) {             throw new Exception( "Index out of bound" );         }           return boxes[x][y];     }       public void resetBoard()     {         // initialize white pieces         boxes[ 0 ][ 0 ] = new Spot( 0 , 0 , new Rook( true ));         boxes[ 0 ][ 1 ] = new Spot( 0 , 1 , new Knight( true ));         boxes[ 0 ][ 2 ] = new Spot( 0 , 2 , new Bishop( true ));         //...         boxes[ 1 ][ 0 ] = new Spot( 1 , 0 , new Pawn( true ));         boxes[ 1 ][ 1 ] = new Spot( 1 , 1 , new Pawn( true ));         //...           // initialize black pieces         boxes[ 7 ][ 0 ] = new Spot( 7 , 0 , new Rook( false ));         boxes[ 7 ][ 1 ] = new Spot( 7 , 1 , new Knight( false ));         boxes[ 7 ][ 2 ] = new Spot( 7 , 2 , new Bishop( false ));         //...         boxes[ 6 ][ 0 ] = new Spot( 6 , 0 , new Pawn( false ));         boxes[ 6 ][ 1 ] = new Spot( 6 , 1 , new Pawn( false ));         //...           // initialize remaining boxes without any piece         for ( int i = 2 ; i < 6 ; i++) {             for ( int j = 0 ; j < 8 ; j++) {                 boxes[i][j] = new Spot(i, j, null );             }         }     } } |
Player: An abstract class for player, it can be a human or a computer.
public abstract class Player { Â Â Â Â public boolean whiteSide; Â Â Â Â public boolean humanPlayer; Â Â Â Â Â Â public boolean isWhiteSide() Â Â Â Â { Â Â Â Â Â Â Â Â return this .whiteSide; Â Â Â Â } Â Â Â Â public boolean isHumanPlayer() Â Â Â Â { Â Â Â Â Â Â Â Â return this .humanPlayer; Â Â Â Â } } Â Â public class HumanPlayer extends Player { Â Â Â Â Â Â public HumanPlayer( boolean whiteSide) Â Â Â Â { Â Â Â Â Â Â Â Â this .whiteSide = whiteSide; Â Â Â Â Â Â Â Â this .humanPlayer = true ; Â Â Â Â } } Â Â public class ComputerPlayer extends Player { Â Â Â Â Â Â public ComputerPlayer( boolean whiteSide) Â Â Â Â { Â Â Â Â Â Â Â Â this .whiteSide = whiteSide; Â Â Â Â Â Â Â Â this .humanPlayer = false ; Â Â Â Â } } |
Move: To represent a chess move:
public class Move { Â Â Â Â private Player player; Â Â Â Â private Spot start; Â Â Â Â private Spot end; Â Â Â Â private Piece pieceMoved; Â Â Â Â private Piece pieceKilled; Â Â Â Â private boolean castlingMove = false ; Â Â Â Â Â Â public Move(Player player, Spot start, Spot end) Â Â Â Â { Â Â Â Â Â Â Â Â this .player = player; Â Â Â Â Â Â Â Â this .start = start; Â Â Â Â Â Â Â Â this .end = end; Â Â Â Â Â Â Â Â this .pieceMoved = start.getPiece(); Â Â Â Â } Â Â Â Â Â Â public boolean isCastlingMove() Â Â Â Â { Â Â Â Â Â Â Â Â return this .castlingMove; Â Â Â Â } Â Â Â Â Â Â public void setCastlingMove( boolean castlingMove) Â Â Â Â { Â Â Â Â Â Â Â Â this .castlingMove = castlingMove; Â Â Â Â } } |
public enum GameStatus { Â Â Â Â ACTIVE, Â Â Â Â BLACK_WIN, Â Â Â Â WHITE_WIN, Â Â Â Â FORFEIT, Â Â Â Â STALEMATE, Â Â Â Â RESIGNATION } |
Game: To represent a chess game:
public class Game {     private Player[] players;     private Board board;     private Player currentTurn;     private GameStatus status;     private List<Move> movesPlayed;       private void initialize(Player p1, Player p2)     {         players[ 0 ] = p1;         players[ 1 ] = p2;           board.resetBoard();           if (p1.isWhiteSide()) {             this .currentTurn = p1;         }         else {             this .currentTurn = p2;         }           movesPlayed.clear();     }       public boolean isEnd()     {         return this .getStatus() != GameStatus.ACTIVE;     }       public boolean getStatus()     {         return this .status;     }       public void setStatus(GameStatus status)     {         this .status = status;     }       public boolean playerMove(Player player, int startX,                                 int startY, int endX, int endY)     {         Spot startBox = board.getBox(startX, startY);         Spot endBox = board.getBox(startY, endY);         Move move = new Move(player, startBox, endBox);         return this .makeMove(move, player);     }       private boolean makeMove(Move move, Player player)     {         Piece sourcePiece = move.getStart().getPiece();         if (sourcePiece == null ) {             return false ;         }           // valid player         if (player != currentTurn) {             return false ;         }           if (sourcePiece.isWhite() != player.isWhiteSide()) {             return false ;         }           // valid move?         if (!sourcePiece.canMove(board, move.getStart(),                                             move.getEnd())) {             return false ;         }           // kill?         Piece destPiece = move.getStart().getPiece();         if (destPiece != null ) {             destPiece.setKilled( true );             move.setPieceKilled(destPiece);         }           // castling?         if (sourcePiece != null && sourcePiece instanceof King             && sourcePiece.isCastlingMove()) {             move.setCastlingMove( true );         }           // store the move         movesPlayed.add(move);           // move piece from the stat box to end box         move.getEnd().setPiece(move.getStart().getPiece());         move.getStart.setPiece( null );           if (destPiece != null && destPiece instanceof King) {             if (player.isWhiteSide()) {                 this .setStatus(GameStatus.WHITE_WIN);             }             else {                 this .setStatus(GameStatus.BLACK_WIN);             }         }           // set the current turn to the other player         if ( this .currentTurn == players[ 0 ]) {             this .currentTurn = players[ 1 ];         }         else {             this .currentTurn = players[ 0 ];         }           return true ;     } } |
Reference: http://massivetechinterview.blogspot.com/2015/07/design-chess-game-using-oo-principles.html
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 neveropen!