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!