package chess.model.rules; import chess.model.ChessBoard; import chess.model.Color; import chess.model.Coordinate; import chess.model.Direction; import chess.model.Move; import chess.model.Piece; import chess.model.PieceVisitor; import chess.model.pieces.Bishop; import chess.model.pieces.King; import chess.model.pieces.Knight; import chess.model.pieces.Pawn; import chess.model.pieces.Queen; import chess.model.pieces.Rook; /** * Check if there are pieces in the path of a move. */ public class PiecePathChecker implements PieceVisitor { private final ChessBoard board; private final Move move; public PiecePathChecker(ChessBoard board, Move move) { this.move = move; this.board = board; } public boolean isValid() { if (this.move.getStart().equals(this.move.getFinish())) return false; Piece piece = this.board.pieceAt(move.getStart()); if (piece == null) return false; return visit(piece); } @Override public Boolean visitPiece(Bishop bishop) { return basicCheck(bishop); } @Override public Boolean visitPiece(King king) { return destCheck(king); } @Override public Boolean visitPiece(Knight knight) { return destCheck(knight); } @Override public Boolean visitPiece(Queen queen) { return basicCheck(queen); } @Override public Boolean visitPiece(Rook rook) { return basicCheck(rook); } @Override public Boolean visitPiece(Pawn pawn) { if (!new PermissiveRuleChecker(this.move).isValidFor(pawn)) return false; Direction moveDirection = Direction.fromInt(Direction.findDirection(move).getIndexOffset() * pawn.multiplier()); if (moveDirection == Direction.Front) return testPath(pawn.getColor()) && this.board.pieceAt(this.move.getFinish()) == null; assert moveDirection == Direction.FrontLeft || moveDirection == Direction.FrontRight; if (checkEnPassant()) return true; Piece destPiece = this.board.pieceAt(this.move.getFinish()); if (destPiece == null) return false; return destPiece.getColor() != pawn.getColor(); } private boolean checkEnPassant() { Move lastMove = this.board.getLastMove(); if (lastMove == null) return false; Piece pieceToEat = this.board.pieceAt(lastMove.getFinish()); if (pieceToEat == null || !(pieceToEat instanceof Pawn)) return false; Piece pawn = this.board.pieceAt(this.move.getStart()); if (pieceToEat.getColor() == pawn.getColor()) return false; Direction lastMoveDir = Direction.findDirection(lastMove); if ((lastMoveDir != Direction.Front && lastMoveDir != Direction.Back) || lastMove.traversedCells() != 2) return false; Coordinate middle = lastMove.getMiddle(); if (middle.equals(this.move.getFinish()) && pieceToEat instanceof Pawn) { this.move.setDeadPieceCoords(lastMove.getFinish()); return true; } return false; } private boolean destCheck(Piece piece) { if (!new PermissiveRuleChecker(this.move).isValidFor(piece)) return false; Piece destPiece = board.pieceAt(this.move.getFinish()); if (destPiece == null) return true; return destPiece.getColor() != piece.getColor(); } private boolean basicCheck(Piece piece) { if (!new PermissiveRuleChecker(this.move).isValidFor(piece)) return false; return testPath(piece.getColor()); } private boolean testPath(Color color) { Direction moveDirection = Direction.findDirection(this.move); int distance = this.move.traversedCells(); int stepIndex = move.getStart().toIndex(); for (int step = 0; step < distance; step++) { stepIndex += moveDirection.getIndexOffset(); if (Coordinate.fromIndex(stepIndex).equals(move.getFinish())) { Piece pieceDest = this.board.pieceAt(move.getFinish()); if (pieceDest == null) return true; return pieceDest.getColor() != color; } if (!this.board.isCellEmpty(Coordinate.fromIndex(stepIndex))) return false; } return false; } }