Design a Chess Game

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:

  1. Spot: A spot represents one block of the 8×8 grid and an optional piece.
  2. 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.
  3. Board: Board is an 8×8 set of boxes containing all active chess pieces.
  4. Player: Player class represents one of the participants playing the game.
  5. 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.
  6. 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.
  7. 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:

    filter_none

    edit
    close

    play_arrow

    link
    brightness_4
    code

    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;
        }
    }

    chevron_right

    
    

    Piece: An abstract class to represent common functionality of all chess pieces:

    filter_none

    edit
    close

    play_arrow

    link
    brightness_4
    code

    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);
    }

    chevron_right

    
    

    King: To represent King as a chess piece:

    filter_none

    edit
    close

    play_arrow

    link
    brightness_4
    code

    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
        }
    }

    chevron_right

    
    

    Knight: To represent Knight as a chess piece

    filter_none

    edit
    close

    play_arrow

    link
    brightness_4
    code

    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;
        }
    }

    chevron_right

    
    

    Similarly, we can create classes for other pieces like Queen, Pawns, Rooks, Bishops etc.

    Board: To represent a chess board:

    filter_none

    edit
    close

    play_arrow

    link
    brightness_4
    code

    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);
                }
            }
        }
    }

    chevron_right

    
    

    Player: An abstract class for player, it can be a human or a computer.

    filter_none

    edit
    close

    play_arrow

    link
    brightness_4
    code

    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;
        }
    }

    chevron_right

    
    

    Move: To represent a chess move:

    filter_none

    edit
    close

    play_arrow

    link
    brightness_4
    code

    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;
        }
    }

    chevron_right

    
    

    filter_none

    edit
    close

    play_arrow

    link
    brightness_4
    code

    public enum GameStatus {
        ACTIVE,
        BLACK_WIN,
        WHITE_WIN,
        FORFEIT,
        STALEMATE,
        RESIGNATION
    }

    chevron_right

    
    

    Game: To represent a chess game:

    filter_none

    edit
    close

    play_arrow

    link
    brightness_4
    code

    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;
        }
    }

    chevron_right

    
    

    Reference: http://massivetechinterview.blogspot.com/2015/07/design-chess-game-using-oo-principles.html

    Attention reader! Don’t stop learning now. Get hold of all the important DSA concepts with the DSA Self Paced Course at a student-friendly price and become industry ready.




    My Personal Notes arrow_drop_up

    Tech Lead & Mentor at GeeksforGeeks || Ex - Adobe, Paytm || NIT Allahabad

    If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

    Please Improve this article if you find anything incorrect by clicking on the "Improve Article" button below.



    Improved By : shutovleonid