Chess game design


fig 1.
fig 1.

Translation from English with adaptation

Original author:
shashipk11
@shashipk11
https://auth.geeksforgeeks.org/user/shashipk11/articles

Links to the original:
https://www.geeksforgeeks.org/design-a-chess-game/
https://massivetechinterview.blogspot.com/2015/07/design-chess-game-using-oo-principles.html

Difficulty level: Complicated
Last update: 30 Sep, 2020

Formulation of the problem:
The problem is to design a chess game using object-oriented principles.

To the question: Adobe, Amazon, Microsoft, etc.

Decision:
These kinds of questions are asked in an interview to judge a candidate’s object-oriented design skill. So, first of all, we have to think about classes.

Translation Author’s Note:
It would be nice to decide on the structure of the code and build a UML diagram.
Then, having formed connections and relationships, build classes. This approach to design would be more visual and writing code would take less time.

Further in the text: Note. – note of the author of the translation.

The main classes will be:

  1. Cell(Spot class): A cell consists of one grid block and additional elements.

  2. Figure (Piece class) – the base unit of the system.
    Each object of the class figure, or rather the object of the successor of the class Piece, will be located on the cell. The figure (Piece class) will be an abstract class. The successor classes (Pawn (Pawn class), Knight (King class), Queen (Queen class), Rook (Rook class), King (Knight class), Bishop or Officer (Bishop class) implement abstract operations.

Note of the author of the translation: the word – “Bishop” can be translated as an officer in this case. This refers to chess pieces, and “Bishop” is not called a chess piece.

  • Board(class Board): a set of cells 8×8.

  • Player(Player class) represents one of the participants in the game.

  • Movement (Move class): Movement (move) represents a move in the game, contains a starting and ending cell. The movement will also contain a track of the player who is making the moves.

  • Game (Game class): This class controls the flow of the game.
    It contains the path and keeps track of the path of all the game moves that the player has made, as well as the final result of the game.

Let’s take a look at the details. The code is clear and speaks for itself. You can take a look at the properties/variables and methods of various classes.

To represent a cell (cell) on a chessboard:

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 (Piece class): An abstract class to represent the general 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 (Knight class): represents a chess piece – the king:

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 such as queen, pawns, rooks, bishops, etc.

Board (Board class): to represent a chessboard:

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

Note.

public Spot getBox(int x, int y) throws Exception {

    if (x < 0 || x > 7 || y < 0 || y > 7) {
        throw new Exception("Index out of bound");
    }

Player(class Player): The abstract class player. It can be a person or a computer.

Note. In the sense that the game can be: Man-Man, Computer-Computer,
Man-Computer.

public abstract class Player {
    public boolean whiteSide;
    public boolean humanPlayer;
  
    public boolean isWhiteSide()
    {
        return this.whiteSide;
    }
    public boolean isHumanPlayer()
    {
        return this.humanPlayer;
    }
}

Class: HumanPlayer

public class HumanPlayer extends Player {
  
    public HumanPlayer(boolean whiteSide)
    {
        this.whiteSide = whiteSide;
        this.humanPlayer = true;
    }
}

Class: ComputerPlayer

public class ComputerPlayer extends Player {
  
    public ComputerPlayer(boolean whiteSide)
    {
        this.whiteSide = whiteSide;
        this.humanPlayer = false;
    }
}

Movement (class Move): To represent movement (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;
    }
}

Enumeration: Game Status

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

Game(Game class): to represent a game of chess:

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

Thank you for your attention. There will be time and desire – I will review the code.
In this text, I left the code as is, as it is written in the original.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *