From 40ef31dd1fa545650d29b69af0d5f0521ce10f90 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sat, 13 Jul 2019 11:38:44 +0200 Subject: [PATCH] Added castling, fixed some minor bugs --- src/dev/kske/chess/board/Board.java | 53 ++++++++++++++++++++-- src/dev/kske/chess/board/King.java | 45 +++++++++++++++++- src/dev/kske/chess/board/Piece.java | 20 ++++++-- src/dev/kske/chess/game/NaturalPlayer.java | 3 +- src/dev/kske/chess/ui/GameModeDialog.java | 2 + src/dev/kske/chess/ui/MainWindow.java | 1 + 6 files changed, 112 insertions(+), 12 deletions(-) diff --git a/src/dev/kske/chess/board/Board.java b/src/dev/kske/chess/board/Board.java index 93bd777..546ccde 100644 --- a/src/dev/kske/chess/board/Board.java +++ b/src/dev/kske/chess/board/Board.java @@ -50,7 +50,7 @@ public class Board implements Cloneable { new int[][] { new int[] { -2, -1, -1, -1, -1, -1, -1, 2 }, new int[] { -1, 0, 0, 0, 0, 0, 0, -1 }, new int[] { -1, 0, 1, 1, 1, 1, 0, -1 }, new int[] { -1, 1, 1, 1, 1, 1, 1, -1 }, new int[] { -1, 0, 1, 1, 1, 1, 0, -1 }, new int[] { -1, 1, 1, 1, 1, 1, 1, -1 }, - new int[] { -1, 1, 0, 0, 0, 0, 1, -1 }, new int[] { -2, -1, -1, -1, -1, -1, -2 } }); + new int[] { -1, 1, 0, 0, 0, 0, 1, -1 }, new int[] { -2, -1, -1, -1, -1, -1, -1, -2 } }); positionScores.put(Type.PAWN, new int[][] { new int[] { 0, 0, 0, 0, 0, 0, 0, 0 }, new int[] { 5, 5, 5, 5, 5, 5, 5, 5 }, new int[] { 1, 1, 2, 3, 3, 2, 1, 1 }, new int[] { 0, 0, 1, 3, 3, 1, 0, 0 }, @@ -75,6 +75,9 @@ public class Board implements Cloneable { Piece piece = getPos(move); if (piece == null || !piece.isValidMove(move)) return false; else { + // Set type after validation + if (move.type == Move.Type.UNKNOWN) move.type = Move.Type.NORMAL; + // Move piece move(move); @@ -104,13 +107,34 @@ public class Board implements Cloneable { // TODO: Select promotion setDest(move, new Queen(piece.getColor(), this)); break; + case CASTLING: + // Move the king + setDest(move, piece); + setPos(move, null); + + // Move the rook + Move rookMove = move.dest.x == 6 ? new Move(7, move.pos.y, 5, move.pos.y) // Kingside + : new Move(0, move.pos.y, 3, move.pos.y); // Queenside + + // Move the rook + setDest(rookMove, getPos(rookMove)); + setPos(rookMove, null); + + getDest(rookMove).incMoveCounter(); + break; case UNKNOWN: - System.err.printf("Unknown move %s found!%n", move); + System.err.printf("Move of unknown type %s found!%n", move); case NORMAL: setDest(move, piece); setPos(move, null); + break; + default: + System.err.printf("Move %s of unimplemented type found!%n", move); } + // Increment move counter + getDest(move).incMoveCounter(); + // Update the king's position if the moved piece is the king if (piece.getType() == Type.KING) kingPos.put(piece.getColor(), move.dest); @@ -127,19 +151,38 @@ public class Board implements Cloneable { Piece capturedPiece = loggedMove.capturedPiece; switch (move.type) { - case CASTLING: - case EN_PASSANT: case PAWN_PROMOTION: setPos(move, new Pawn(getDest(move).getColor(), this)); setDest(move, capturedPiece); break; + case CASTLING: + // Move the king + setPos(move, getDest(move)); + setDest(move, null); + + // Move the rook + Move rookMove = move.dest.x == 6 ? new Move(5, move.pos.y, 7, move.pos.y) // Kingside + : new Move(3, move.pos.y, 0, move.pos.y); // Queenside + + // Move the rook + setDest(rookMove, getPos(rookMove)); + setPos(rookMove, null); + + getDest(rookMove).decMoveCounter(); + break; case UNKNOWN: - System.err.printf("Unknown move %s found!%n", move); + System.err.printf("Move of unknown type %s found!%n", move); case NORMAL: setPos(move, getDest(move)); setDest(move, capturedPiece); + break; + default: + System.err.printf("Move %s of unimplemented type found!%n", move); } + // Decrement move counter + getPos(move).decMoveCounter(); + // Update the king's position if the moved piece is the king if (getPos(move).getType() == Type.KING) kingPos.put(getPos(move).getColor(), move.pos); diff --git a/src/dev/kske/chess/board/King.java b/src/dev/kske/chess/board/King.java index 1b6bbd2..7c0ad2e 100644 --- a/src/dev/kske/chess/board/King.java +++ b/src/dev/kske/chess/board/King.java @@ -17,7 +17,26 @@ public class King extends Piece { @Override public boolean isValidMove(Move move) { - return move.xDist <= 1 && move.yDist <= 1 && isFreePath(move); + // Castling + if (getMoveCounter() == 0 && move.xDist == 2 && move.yDist == 0) { + + // Kingside + if (board.getBoardArr()[7][move.pos.y] != null && board.getBoardArr()[7][move.pos.y].getType() == Type.ROOK + && isFreePath(new Move(new Position(5, move.pos.y), new Position(7, move.pos.y)))) { + move.type = Move.Type.CASTLING; + return true; + } + + // Queenside + if (board.getBoardArr()[0][move.pos.y] != null && board.getBoardArr()[0][move.pos.y].getType() == Type.ROOK + && isFreePath(new Move(new Position(1, move.pos.y), new Position(4, move.pos.y)))) { + move.type = Move.Type.CASTLING; + return true; + } + + } + + return move.xDist <= 1 && move.yDist <= 1 && checkDestination(move); } @Override @@ -29,9 +48,33 @@ public class King extends Piece { Move move = new Move(pos, new Position(i, j)); if (board.getDest(move) == null || board.getDest(move).getColor() != getColor()) moves.add(move); } + + // Castling + // TODO: Check attacked squares in between + // TODO: Castling out of check? + if (getMoveCounter() == 0) { + + // Kingside + if (board.getBoardArr()[7][pos.y] != null && board.getBoardArr()[7][pos.y].getType() == Type.ROOK + && isFreePath(new Move(new Position(5, pos.y), new Position(7, pos.y)))) + moves.add(new Move(pos, new Position(6, pos.y), Move.Type.CASTLING)); + + // Queenside + if (board.getBoardArr()[0][pos.y] != null && board.getBoardArr()[0][pos.y].getType() == Type.ROOK + && isFreePath(new Move(new Position(1, pos.y), new Position(4, pos.y)))) + moves.add(new Move(pos, new Position(2, pos.y), Move.Type.CASTLING)); + } + return moves; } + @Override + protected boolean isFreePath(Move move) { + for (int i = move.pos.x, j = move.pos.y; i != move.dest.x || j != move.dest.y; i += move.xSign, j += move.ySign) + if (board.getBoardArr()[i][j] != null) return false; + return true; + } + @Override public Type getType() { return Type.KING; } } diff --git a/src/dev/kske/chess/board/Piece.java b/src/dev/kske/chess/board/Piece.java index 71efc89..3298a8d 100644 --- a/src/dev/kske/chess/board/Piece.java +++ b/src/dev/kske/chess/board/Piece.java @@ -11,8 +11,9 @@ import java.util.List; */ public abstract class Piece implements Cloneable { - protected Color color; - protected Board board; + private final Color color; + protected Board board; + private int moveCounter; public Piece(Color color, Board board) { this.color = color; @@ -22,10 +23,9 @@ public abstract class Piece implements Cloneable { public List getMoves(Position pos) { List moves = getPseudolegalMoves(pos); for (Iterator iterator = moves.iterator(); iterator.hasNext();) { - Move move = iterator.next(); + Move move = iterator.next(); board.move(move); - if (board.checkCheck(getColor())) - iterator.remove(); + if (board.checkCheck(getColor())) iterator.remove(); board.revert(); } return moves; @@ -66,6 +66,16 @@ public abstract class Piece implements Cloneable { public Color getColor() { return color; } + public int getMoveCounter() { return moveCounter; } + + public void incMoveCounter() { + ++moveCounter; + } + + public void decMoveCounter() { + --moveCounter; + } + public static enum Type { KING, QUEEN, ROOK, KNIGHT, BISHOP, PAWN } diff --git a/src/dev/kske/chess/game/NaturalPlayer.java b/src/dev/kske/chess/game/NaturalPlayer.java index 63a6f96..d346a71 100644 --- a/src/dev/kske/chess/game/NaturalPlayer.java +++ b/src/dev/kske/chess/game/NaturalPlayer.java @@ -7,6 +7,7 @@ import java.util.stream.Collectors; import dev.kske.chess.board.Board; import dev.kske.chess.board.Move; +import dev.kske.chess.board.Move.Type; import dev.kske.chess.board.Piece.Color; import dev.kske.chess.board.Position; import dev.kske.chess.ui.OverlayComponent; @@ -49,7 +50,7 @@ public class NaturalPlayer extends Player { overlayComponent.clearDots(); moveRequested = false; - game.onMove(NaturalPlayer.this, new Move(pos, dest)); + game.onMove(NaturalPlayer.this, new Move(pos, dest, Type.UNKNOWN)); pos = null; } } diff --git a/src/dev/kske/chess/ui/GameModeDialog.java b/src/dev/kske/chess/ui/GameModeDialog.java index 6c64172..9c37a80 100644 --- a/src/dev/kske/chess/ui/GameModeDialog.java +++ b/src/dev/kske/chess/ui/GameModeDialog.java @@ -79,5 +79,7 @@ public class GameModeDialog extends JDialog { dispose(); }); getContentPane().add(btnAI2); + + setLocationRelativeTo(null); } } diff --git a/src/dev/kske/chess/ui/MainWindow.java b/src/dev/kske/chess/ui/MainWindow.java index 9948987..f6c2630 100644 --- a/src/dev/kske/chess/ui/MainWindow.java +++ b/src/dev/kske/chess/ui/MainWindow.java @@ -64,6 +64,7 @@ public class MainWindow { btnRestart.addActionListener((evt) -> System.err.println("Resetting not implemented!")); toolPanel.add(btnRestart); mframe.pack(); + mframe.setLocationRelativeTo(null); // Display dialog for game mode selection new GameModeDialog(boardPane).setVisible(true);