en passant rule
This commit is contained in:
@@ -3,5 +3,12 @@ package chess.controller;
|
||||
import chess.model.Game;
|
||||
|
||||
public abstract class PlayerCommand extends Command{
|
||||
public abstract CommandResult undo(Game game, OutputSystem outputSystem);
|
||||
|
||||
public CommandResult undo(Game game, OutputSystem outputSystem) {
|
||||
CommandResult result = undoImpl(game, outputSystem);
|
||||
game.updateLastMove();
|
||||
return result;
|
||||
}
|
||||
|
||||
protected abstract CommandResult undoImpl(Game game, OutputSystem outputSystem);
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ public class CastlingCommand extends PlayerCommand {
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandResult undo(Game game, OutputSystem outputSystem) {
|
||||
protected CommandResult undoImpl(Game game, OutputSystem outputSystem) {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'undo'");
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ public class GrandCastlingCommand extends PlayerCommand {
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandResult undo(Game game, OutputSystem outputSystem) {
|
||||
protected CommandResult undoImpl(Game game, OutputSystem outputSystem) {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'undo'");
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import chess.model.Piece;
|
||||
import chess.model.visitor.PiecePathChecker;
|
||||
|
||||
public class MoveCommand extends PlayerCommand {
|
||||
|
||||
|
||||
private final Move move;
|
||||
private Piece deadPiece;
|
||||
|
||||
@@ -42,7 +42,7 @@ public class MoveCommand extends PlayerCommand {
|
||||
if (!valid)
|
||||
return CommandResult.NotAllowed;
|
||||
|
||||
this.deadPiece = board.pieceAt(move.getFinish());
|
||||
this.deadPiece = board.pieceAt(move.getDeadPieceCoords());
|
||||
board.applyMove(move);
|
||||
|
||||
if (board.isKingInCheck(game.getPlayerTurn())) {
|
||||
@@ -50,14 +50,15 @@ public class MoveCommand extends PlayerCommand {
|
||||
return CommandResult.NotAllowed;
|
||||
}
|
||||
|
||||
if (game.pawnShouldBePromoted())
|
||||
if (game.pawnShouldBePromoted())
|
||||
return CommandResult.ActionNeeded;
|
||||
|
||||
board.setLastMove(this.move);
|
||||
return CommandResult.Moved;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandResult undo(Game game, OutputSystem outputSystem) {
|
||||
protected CommandResult undoImpl(Game game, OutputSystem outputSystem) {
|
||||
final ChessBoard board = game.getBoard();
|
||||
|
||||
board.undoMove(move, deadPiece);
|
||||
|
||||
@@ -75,7 +75,7 @@ public class PromoteCommand extends PlayerCommand {
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandResult undo(Game game, OutputSystem outputSystem) {
|
||||
protected CommandResult undoImpl(Game game, OutputSystem outputSystem) {
|
||||
final ChessBoard board = game.getBoard();
|
||||
|
||||
Piece promoted = board.pieceAt(this.pieceCoords);
|
||||
|
||||
@@ -25,6 +25,7 @@ public class ChessBoard {
|
||||
}
|
||||
|
||||
private final Cell[][] cells;
|
||||
private Move lastVirtualMove;
|
||||
private Move lastMove;
|
||||
private Piece lastEjectedPiece;
|
||||
|
||||
@@ -35,35 +36,38 @@ public class ChessBoard {
|
||||
this.cells[i][j] = new Cell();
|
||||
}
|
||||
}
|
||||
this.lastVirtualMove = null;
|
||||
this.lastMove = null;
|
||||
this.lastEjectedPiece = null;
|
||||
}
|
||||
|
||||
public void applyMove(Move move) {
|
||||
assert move.isValid() : "Invalid move !";
|
||||
Piece deadPiece = pieceAt(move.getFinish());
|
||||
Piece deadPiece = pieceAt(move.getDeadPieceCoords());
|
||||
if (deadPiece != null) {
|
||||
this.lastEjectedPiece = deadPiece;
|
||||
} else {
|
||||
this.lastEjectedPiece = null;
|
||||
}
|
||||
Piece movingPiece = pieceAt(move.getStart());
|
||||
pieceComes(movingPiece, move.getFinish());
|
||||
pieceLeaves(move.getDeadPieceCoords());
|
||||
pieceLeaves(move.getStart());
|
||||
pieceComes(movingPiece, move.getFinish());
|
||||
movingPiece.move();
|
||||
this.lastMove = move;
|
||||
this.lastVirtualMove = move;
|
||||
}
|
||||
|
||||
public void undoLastMove() {
|
||||
assert this.lastMove != null: "Can't undo at the beginning!";
|
||||
assert this.lastVirtualMove != null: "Can't undo at the beginning!";
|
||||
|
||||
undoMove(this.lastMove, this.lastEjectedPiece);
|
||||
undoMove(this.lastVirtualMove, this.lastEjectedPiece);
|
||||
}
|
||||
|
||||
public void undoMove(Move move, Piece deadPiece) {
|
||||
Piece movingPiece = pieceAt(move.getFinish());
|
||||
pieceComes(movingPiece, move.getStart());
|
||||
pieceComes(deadPiece, move.getFinish());
|
||||
pieceLeaves(move.getFinish());
|
||||
pieceComes(deadPiece, move.getDeadPieceCoords());
|
||||
movingPiece.unMove();
|
||||
}
|
||||
|
||||
@@ -177,4 +181,12 @@ public class ChessBoard {
|
||||
return result;
|
||||
}
|
||||
|
||||
public Move getLastMove() {
|
||||
return this.lastMove;
|
||||
}
|
||||
|
||||
public void setLastMove(Move lastMove) {
|
||||
this.lastMove = lastMove;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import java.util.EmptyStackException;
|
||||
import java.util.Stack;
|
||||
|
||||
import chess.controller.PlayerCommand;
|
||||
import chess.controller.commands.MoveCommand;
|
||||
import chess.model.visitor.PawnIdentifier;
|
||||
|
||||
public class Game {
|
||||
@@ -99,4 +100,14 @@ public class Game {
|
||||
}
|
||||
}
|
||||
|
||||
public void updateLastMove() {
|
||||
if (this.movesHistory.isEmpty())
|
||||
return;
|
||||
|
||||
PlayerCommand last = this.movesHistory.getLast();
|
||||
if (last instanceof MoveCommand move) {
|
||||
this.board.setLastMove(move.getMove());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,10 +3,12 @@ package chess.model;
|
||||
public class Move {
|
||||
private final Coordinate start;
|
||||
private final Coordinate finish;
|
||||
private Coordinate deadPieceCoords;
|
||||
|
||||
public Move(Coordinate start, Coordinate finish) {
|
||||
this.start = start;
|
||||
this.finish = finish;
|
||||
this.deadPieceCoords = finish;
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
@@ -39,4 +41,16 @@ public class Move {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public Coordinate getMiddle() {
|
||||
return Coordinate.fromIndex((getStart().toIndex() + getFinish().toIndex()) / 2);
|
||||
}
|
||||
|
||||
public void setDeadPieceCoords(Coordinate deadCoords) {
|
||||
this.deadPieceCoords = deadCoords;
|
||||
}
|
||||
|
||||
public Coordinate getDeadPieceCoords() {
|
||||
return deadPieceCoords;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -35,31 +35,27 @@ public class PiecePathChecker implements PieceVisitor<Boolean> {
|
||||
|
||||
@Override
|
||||
public Boolean visitPiece(Bishop bishop) {
|
||||
if (!new PermissiveRuleChecker(this.move).isValidFor(bishop))
|
||||
return false;
|
||||
return testPath(bishop.getColor());
|
||||
return basicCheck(bishop);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean visitPiece(King king) {
|
||||
if (!new PermissiveRuleChecker(this.move).isValidFor(king))
|
||||
return false;
|
||||
|
||||
Piece destPiece = board.pieceAt(this.move.getFinish());
|
||||
if (destPiece == null)
|
||||
return true;
|
||||
return destPiece.getColor() != king.getColor();
|
||||
return destCheck(king);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean visitPiece(Knight knight) {
|
||||
if (!new PermissiveRuleChecker(this.move).isValidFor(knight))
|
||||
return false;
|
||||
return destCheck(knight);
|
||||
}
|
||||
|
||||
Piece destPiece = board.pieceAt(this.move.getFinish());
|
||||
if (destPiece == null)
|
||||
return true;
|
||||
return destPiece.getColor() != knight.getColor();
|
||||
@Override
|
||||
public Boolean visitPiece(Queen queen) {
|
||||
return basicCheck(queen);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean visitPiece(Rook rook) {
|
||||
return basicCheck(rook);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -74,6 +70,9 @@ public class PiecePathChecker implements PieceVisitor<Boolean> {
|
||||
|
||||
assert moveDirection == Direction.FrontLeft || moveDirection == Direction.FrontRight;
|
||||
|
||||
if (checkEnPassant())
|
||||
return true;
|
||||
|
||||
Piece destPiece = this.board.pieceAt(this.move.getFinish());
|
||||
if (destPiece == null)
|
||||
return false;
|
||||
@@ -81,18 +80,44 @@ public class PiecePathChecker implements PieceVisitor<Boolean> {
|
||||
return destPiece.getColor() != pawn.getColor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean visitPiece(Queen queen) {
|
||||
if (!new PermissiveRuleChecker(this.move).isValidFor(queen))
|
||||
private boolean checkEnPassant() {
|
||||
Move lastMove = this.board.getLastMove();
|
||||
|
||||
if (lastMove == null)
|
||||
return false;
|
||||
return testPath(queen.getColor());
|
||||
|
||||
Piece pieceToEat = this.board.pieceAt(lastMove.getFinish());
|
||||
|
||||
if (pieceToEat == null)
|
||||
return false;
|
||||
|
||||
Piece pawn = this.board.pieceAt(this.move.getStart());
|
||||
|
||||
if (pieceToEat.getColor() == pawn.getColor())
|
||||
return false;
|
||||
|
||||
if (lastMove.getMiddle().equals(this.move.getFinish())
|
||||
&& new PawnIdentifier(pieceToEat.getColor()).isPawn(pieceToEat)) {
|
||||
this.move.setDeadPieceCoords(lastMove.getFinish());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean visitPiece(Rook rook) {
|
||||
if (!new PermissiveRuleChecker(this.move).isValidFor(rook))
|
||||
private boolean destCheck(Piece piece) {
|
||||
if (!new PermissiveRuleChecker(this.move).isValidFor(piece))
|
||||
return false;
|
||||
return testPath(rook.getColor());
|
||||
|
||||
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) {
|
||||
|
||||
Reference in New Issue
Block a user