package chess.model; import java.util.ArrayList; import java.util.List; import chess.model.visitor.KingIdentifier; import chess.model.visitor.PiecePathChecker; public class ChessBoard { public static class Cell { private Piece piece; public Cell() { this.piece = null; } public Piece getPiece() { return piece; } public void setPiece(Piece piece) { this.piece = piece; } } private final Cell[][] cells; private Move lastMove; private Piece lastEjectedPiece; public ChessBoard() { this.cells = new Cell[Coordinate.VALUE_MAX][Coordinate.VALUE_MAX]; for (int i = 0; i < Coordinate.VALUE_MAX; i++) { for (int j = 0; j < Coordinate.VALUE_MAX; j++) { this.cells[i][j] = new Cell(); } } this.lastMove = null; this.lastEjectedPiece = null; } public void applyMove(Move move) { assert move.isValid() : "Invalid move !"; Piece deadPiece = pieceAt(move.getFinish()); if (deadPiece != null) { this.lastEjectedPiece = deadPiece; } else { this.lastEjectedPiece = null; } Piece movingPiece = pieceAt(move.getStart()); pieceComes(movingPiece, move.getFinish()); pieceLeaves(move.getStart()); movingPiece.move(); this.lastMove = move; } public void undoLastMove() { assert this.lastMove != null: "Can't undo at the beginning!"; Move move = this.lastMove; Piece movingPiece = pieceAt(move.getFinish()); pieceComes(movingPiece, move.getStart()); pieceLeaves(move.getFinish()); movingPiece.unMove(); if (this.lastEjectedPiece == null) return; Piece piece = this.lastEjectedPiece; pieceComes(piece, move.getFinish()); } public boolean isCellEmpty(Coordinate coordinate) { return pieceAt(coordinate) == null; } public Piece pieceAt(Coordinate coordinate) { if (!coordinate.isValid()) return null; return cellAt(coordinate).getPiece(); } public void clearBoard() { for (int i = 0; i < Coordinate.VALUE_MAX; i++) { for (int j = 0; j < Coordinate.VALUE_MAX; j++) { pieceLeaves(new Coordinate(i, j)); } } } private Cell cellAt(Coordinate coordinate) { return this.cells[coordinate.getX()][coordinate.getY()]; } public void pieceComes(Piece piece, Coordinate coordinate) { cellAt(coordinate).setPiece(piece); } public void pieceLeaves(Coordinate coordinate) { cellAt(coordinate).setPiece(null); } public Coordinate findKing(Color color) { KingIdentifier kingIdentifier = new KingIdentifier(color); for (int i = 0; i < Coordinate.VALUE_MAX; i++) { for (int j = 0; j < Coordinate.VALUE_MAX; j++) { Coordinate coordinate = new Coordinate(i, j); Piece piece = pieceAt(coordinate); if (piece != null && kingIdentifier.visit(piece)) { return coordinate; } } } assert false : "No king found ?!"; return null; } public boolean isKingInCheck(Color color) { Coordinate kingPos = findKing(color); assert kingPos.isValid() : "King position is invalid!"; for (int i = 0; i < Coordinate.VALUE_MAX; i++) { for (int j = 0; j < Coordinate.VALUE_MAX; j++) { Coordinate attackCoords = new Coordinate(i, j); Piece attackPiece = pieceAt(attackCoords); if (attackPiece == null) continue; PiecePathChecker checker = new PiecePathChecker(this, new Move(attackCoords, kingPos)); if (checker.isValid()) return true; } } return false; } public boolean hasAllowedMoves(Color player) { for (int i = 0; i < Coordinate.VALUE_MAX; i++) { for (int j = 0; j < Coordinate.VALUE_MAX; j++) { Coordinate attackCoords = new Coordinate(i, j); Piece attackPiece = pieceAt(attackCoords); if (attackPiece == null) continue; if (attackPiece.getColor() != player) continue; if (!getAllowedMoves(attackCoords).isEmpty()) return true; } } return false; } public List getAllowedMoves(Coordinate pieceCoords) { Piece piece = pieceAt(pieceCoords); if (piece == null) return null; Color player = piece.getColor(); List result = new ArrayList<>(); for (int i = 0; i < Coordinate.VALUE_MAX; i++) { for (int j = 0; j < Coordinate.VALUE_MAX; j++) { Coordinate destination = new Coordinate(i, j); Move move = new Move(pieceCoords, destination); PiecePathChecker piecePathChecker = new PiecePathChecker(this, move); if (!piecePathChecker.isValid()) continue; applyMove(move); if (!isKingInCheck(player)) result.add(destination); undoLastMove(); } } return result; } }