Как стать автором
Обновить

Дизайн шахматной игры

ООП *Java *Алгоритмы *Разработка игр *
Recovery mode
Перевод
Автор оригинала: @shashipk11
рис 1.
рис 1.

Перевод с английского с адаптацией

Автор оригинала:
shashipk11
@shashipk11
https://auth.geeksforgeeks.org/user/shashipk11/articles

Ссылки на оригинал:
https://www.geeksforgeeks.org/design-a-chess-game/
https://massivetechinterview.blogspot.com/2015/07/design-chess-game-using-oo-principles.html

Уровень сложности: Сложный
Последнее обновление: 30 Сент., 2020

Постановка задачи:
Проблема состоит в том, чтобы разработать шахматную игру с использованием объектно-ориентированных принципов.

На вопрос: Adobe, Amazon, Microsoft и т. д.

Решение:
Эти виды вопросов задаются на интервью, чтобы судить о навыке объектно ориентированного дизайна кандидата. Итак, прежде всего, мы должны подумать о классах.

Примечание автора перевода:
Хорошо было бы определиться со структурой кода и построить UML диаграмму.
Затем сформировав связи и отношения, строить классы. Такой подход к проектированию был бы более наглядным и написание кода отнимало бы меньше времени.

Далее в тексте: Прим. - примечание автора перевода.

Основными классами будут:

  1. Клетка(класс Spot): Клетка представляет из себя один блок сетки и дополнительные элемент.

  2. Фигура (класс Piece) - базовый блок системы.
    Каждый объект класса фигура, а точнее объект наследника класса Piece, будет расположен на клетке. Фигура (класс Piece) будет абстрактным классом. Классы наследники (Пешка(класс Pawn),Конь (класс King), Ферзь (класс Queen), Ладья (класс Rook), Король (класс Knight), Слон или офицер(класс Bishop) ) реализуют абстрактные операции.

Примечание автора перевода: слово - "Bishop" может в данном случае быть переведено как офицер. Имеются в виду шахматные фигуры, и "Епископом" шахматную фигуру не называют.

  • Доска(класс Board): набор клеток 8х8.

  • Игрок(класс Player) представляет одного из участников игры.

  • Движение (класс Move): Движение(ход) представляет ход в игре, содержит стартовую и конечную клетку. Движение также будет содержать трэк игрока, который делает ходы.

  • Игра (класс Game): Этот класс контролирует поток игры.
    Он содержит путь и отслеживает путь всех ходов игры, которые сделал игрок, а также финальный результат игры.

Давайте взглянем на детали. Код ясный и говорит сам за себя. Вы можете взглянуть на свойства/переменные и методы различных классов.

Для представления ячейки(клетки) на шахматной доске:

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): абстрактный класс для представления общей функциональности всех шахматных фигур:

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

Король(класс Knight): представляет шахматную фигуру - короля:

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

Точно так же мы можем создать классы для других фигур, таких как ферзь, пешки, ладьи, слона и т. д.

Доска(класс 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);
            }
        }
    }
}

Прим.

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): Абстрактный класс игрок. Он может представлять из себя человека или компьютер.

Прим. В том смысле, что игра может быть: Человек-Человек, Компьютер-Компьютер,
Человек-Компьютер.

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

Класс: HumanPlayer

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

Класс: ComputerPlayer

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

Движение(класс 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): для представления игры в шахматы:

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

Спасибо за внимание. Будет время и желание - сделаю ревью кода.
В данном тексте я оставил код как есть, как он написан в оригинале.

Теги:
Хабы:
Рейтинг 0
Просмотры 50
Комментарии Комментировать