diff --git a/app/src/main/java/chess/controller/PlayerCommand.java b/app/src/main/java/chess/controller/PlayerCommand.java index 9a0f76b..42ca979 100644 --- a/app/src/main/java/chess/controller/PlayerCommand.java +++ b/app/src/main/java/chess/controller/PlayerCommand.java @@ -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); } diff --git a/app/src/main/java/chess/controller/commands/CastlingCommand.java b/app/src/main/java/chess/controller/commands/CastlingCommand.java index b4fbba8..51d51f5 100644 --- a/app/src/main/java/chess/controller/commands/CastlingCommand.java +++ b/app/src/main/java/chess/controller/commands/CastlingCommand.java @@ -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'"); } diff --git a/app/src/main/java/chess/controller/commands/GrandCastlingCommand.java b/app/src/main/java/chess/controller/commands/GrandCastlingCommand.java index 11f9fb5..2b319af 100644 --- a/app/src/main/java/chess/controller/commands/GrandCastlingCommand.java +++ b/app/src/main/java/chess/controller/commands/GrandCastlingCommand.java @@ -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'"); } diff --git a/app/src/main/java/chess/controller/commands/MoveCommand.java b/app/src/main/java/chess/controller/commands/MoveCommand.java index 1540c5b..1ff40c5 100644 --- a/app/src/main/java/chess/controller/commands/MoveCommand.java +++ b/app/src/main/java/chess/controller/commands/MoveCommand.java @@ -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); diff --git a/app/src/main/java/chess/controller/commands/PromoteCommand.java b/app/src/main/java/chess/controller/commands/PromoteCommand.java index 318d408..6b49df8 100644 --- a/app/src/main/java/chess/controller/commands/PromoteCommand.java +++ b/app/src/main/java/chess/controller/commands/PromoteCommand.java @@ -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); diff --git a/app/src/main/java/chess/model/ChessBoard.java b/app/src/main/java/chess/model/ChessBoard.java index ae47f79..b3fbb36 100644 --- a/app/src/main/java/chess/model/ChessBoard.java +++ b/app/src/main/java/chess/model/ChessBoard.java @@ -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; + } + } diff --git a/app/src/main/java/chess/model/Game.java b/app/src/main/java/chess/model/Game.java index 83c1b22..2ec63f7 100644 --- a/app/src/main/java/chess/model/Game.java +++ b/app/src/main/java/chess/model/Game.java @@ -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()); + } + } + } diff --git a/app/src/main/java/chess/model/Move.java b/app/src/main/java/chess/model/Move.java index d4db5dd..02b58bc 100644 --- a/app/src/main/java/chess/model/Move.java +++ b/app/src/main/java/chess/model/Move.java @@ -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; + } + } diff --git a/app/src/main/java/chess/model/visitor/PiecePathChecker.java b/app/src/main/java/chess/model/visitor/PiecePathChecker.java index 02f5036..0a58c00 100644 --- a/app/src/main/java/chess/model/visitor/PiecePathChecker.java +++ b/app/src/main/java/chess/model/visitor/PiecePathChecker.java @@ -35,31 +35,27 @@ public class PiecePathChecker implements PieceVisitor { @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 { 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 { 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) {