diff --git a/app/src/main/java/chess/controller/commands/CastlingCommand.java b/app/src/main/java/chess/controller/commands/CastlingCommand.java index 51d51f5..1f48004 100644 --- a/app/src/main/java/chess/controller/commands/CastlingCommand.java +++ b/app/src/main/java/chess/controller/commands/CastlingCommand.java @@ -2,23 +2,62 @@ package chess.controller.commands; import chess.controller.OutputSystem; import chess.controller.PlayerCommand; +import chess.model.ChessBoard; +import chess.model.Color; +import chess.model.Coordinate; import chess.model.Game; +import chess.model.Move; public class CastlingCommand extends PlayerCommand { + private Move kingMove; + private Move rookMove; + private final boolean bigCastling; + + public CastlingCommand(boolean bigCastling) { + this.bigCastling = bigCastling; + } + @Override public CommandResult execute(Game game, OutputSystem outputSystem) { // we must promote the pending pawn before if (game.pawnShouldBePromoted()) return CommandResult.NotAllowed; - return CommandResult.NotAllowed; + final ChessBoard board = game.getBoard(); + + if (bigCastling && !board.canBigCastle(game.getPlayerTurn())) + return CommandResult.NotAllowed; + + if (!bigCastling && !board.canSmallCastle(game.getPlayerTurn())) + return CommandResult.NotAllowed; + + int rookBeginX = bigCastling ? 0 : 7; + int rookEndX = bigCastling ? 3 : 5; + + int kingBeginX = 4; + int kingEndX = bigCastling ? 2 : 6; + + int colorLine = game.getPlayerTurn() == Color.White ? 7 : 0; + + Coordinate kingCoords = new Coordinate(kingBeginX, colorLine); + Coordinate rookCoords = new Coordinate(rookBeginX, colorLine); + + this.kingMove = new Move(kingCoords, new Coordinate(kingEndX, colorLine)); + this.rookMove = new Move(rookCoords, new Coordinate(rookEndX, colorLine)); + + board.applyMove(this.kingMove); + board.applyMove(this.rookMove); + + return CommandResult.Moved; } @Override protected CommandResult undoImpl(Game game, OutputSystem outputSystem) { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'undo'"); + game.getBoard().undoMove(this.kingMove, null); + game.getBoard().undoMove(this.rookMove, null); + + return CommandResult.Moved; } } diff --git a/app/src/main/java/chess/controller/commands/GrandCastlingCommand.java b/app/src/main/java/chess/controller/commands/GrandCastlingCommand.java deleted file mode 100644 index 2b319af..0000000 --- a/app/src/main/java/chess/controller/commands/GrandCastlingCommand.java +++ /dev/null @@ -1,24 +0,0 @@ -package chess.controller.commands; - -import chess.controller.OutputSystem; -import chess.controller.PlayerCommand; -import chess.model.Game; - -public class GrandCastlingCommand extends PlayerCommand { - - @Override - public CommandResult execute(Game game, OutputSystem outputSystem) { - // we must promote the pending pawn before - if (game.pawnShouldBePromoted()) - return CommandResult.NotAllowed; - - return CommandResult.NotAllowed; - } - - @Override - 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/PromoteCommand.java b/app/src/main/java/chess/controller/commands/PromoteCommand.java index 6b49df8..fcdf853 100644 --- a/app/src/main/java/chess/controller/commands/PromoteCommand.java +++ b/app/src/main/java/chess/controller/commands/PromoteCommand.java @@ -9,7 +9,6 @@ import chess.model.Game; import chess.model.Piece; import chess.model.pieces.Bishop; import chess.model.pieces.Knight; -import chess.model.pieces.Pawn; import chess.model.pieces.Queen; import chess.model.pieces.Rook; import chess.model.visitor.PawnIdentifier; @@ -25,9 +24,12 @@ public class PromoteCommand extends PlayerCommand { private final PromoteType promoteType; private Coordinate pieceCoords; + private Piece oldPawn; public PromoteCommand(PromoteType promoteType) { this.promoteType = promoteType; + this.pieceCoords = null; + this.oldPawn = null; } @Override @@ -50,6 +52,7 @@ public class PromoteCommand extends PlayerCommand { if (destY != enemyLine) return CommandResult.NotAllowed; + this.oldPawn = pawn; board.pieceComes(createPiece(this.promoteType, pawn.getColor()), this.pieceCoords); return CommandResult.Moved; @@ -82,10 +85,11 @@ public class PromoteCommand extends PlayerCommand { assert promoted != null; - Color player = promoted.getColor(); - board.pieceComes(new Pawn(player), this.pieceCoords); + board.pieceComes(this.oldPawn, this.pieceCoords); - return CommandResult.ActionNeeded; + game.getLastAction().undo(game, outputSystem); + + return CommandResult.Moved; } } diff --git a/app/src/main/java/chess/model/ChessBoard.java b/app/src/main/java/chess/model/ChessBoard.java index b3fbb36..f74e330 100644 --- a/app/src/main/java/chess/model/ChessBoard.java +++ b/app/src/main/java/chess/model/ChessBoard.java @@ -58,7 +58,7 @@ public class ChessBoard { } public void undoLastMove() { - assert this.lastVirtualMove != null: "Can't undo at the beginning!"; + assert this.lastVirtualMove != null : "Can't undo at the beginning!"; undoMove(this.lastVirtualMove, this.lastEjectedPiece); } @@ -181,6 +181,45 @@ public class ChessBoard { return result; } + private boolean canCastle(Color color, int rookX, Direction kingDirection) { + if (isKingInCheck(color)) + return false; + + int colorLine = color == Color.White ? 7 : 0; + + Coordinate kingCoords = new Coordinate(4, colorLine); + Coordinate rookCoords = new Coordinate(rookX, colorLine); + Piece king = pieceAt(kingCoords); + Piece rook = pieceAt(rookCoords); + + if (king == null || rook == null || king.hasMoved() || rook.hasMoved()) + return false; + + for (int step = 1; step <= 2; step++) { + Coordinate dest = Coordinate.fromIndex(kingCoords.toIndex() + step * kingDirection.getIndexOffset()); + Piece obstacle = pieceAt(dest); + if (obstacle != null) + return false; + + applyMove(new Move(kingCoords, dest)); + if (isKingInCheck(color)) { + undoLastMove(); + return false; + } + undoLastMove(); + } + + return true; + } + + public boolean canSmallCastle(Color color) { + return canCastle(color, 7, Direction.Right); + } + + public boolean canBigCastle(Color color) { + return canCastle(color, 0, Direction.Left); + } + public Move getLastMove() { return this.lastMove; } diff --git a/app/src/main/java/chess/view/simplerender/Window.java b/app/src/main/java/chess/view/simplerender/Window.java index 5284a3f..417d21e 100644 --- a/app/src/main/java/chess/view/simplerender/Window.java +++ b/app/src/main/java/chess/view/simplerender/Window.java @@ -20,7 +20,6 @@ import chess.controller.OutputSystem; import chess.controller.commands.CastlingCommand; import chess.controller.commands.GetAllowedMovesCommand; import chess.controller.commands.GetPieceAtCommand; -import chess.controller.commands.GrandCastlingCommand; import chess.controller.commands.MoveCommand; import chess.controller.commands.PromoteCommand; import chess.controller.commands.PromoteCommand.PromoteType; @@ -61,11 +60,11 @@ public class Window extends JFrame implements OutputSystem { private void buildButtons(JPanel bottom) { castlingButton.addActionListener((event) -> { - sendCommand(new CastlingCommand()); + sendCommand(new CastlingCommand(false)); }); bigCastlingButton.addActionListener((event) -> { - sendCommand(new GrandCastlingCommand()); + sendCommand(new CastlingCommand(true)); }); undoButton.addActionListener((event) -> {