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