Added castling, fixed some minor bugs

This commit is contained in:
Kai S. K. Engelbart 2019-07-13 11:38:44 +02:00
parent 54e73f2b85
commit 40ef31dd1f
6 changed files with 112 additions and 12 deletions

View File

@ -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[][] { 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, 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, 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[][] { 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 }, 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); Piece piece = getPos(move);
if (piece == null || !piece.isValidMove(move)) return false; if (piece == null || !piece.isValidMove(move)) return false;
else { else {
// Set type after validation
if (move.type == Move.Type.UNKNOWN) move.type = Move.Type.NORMAL;
// Move piece // Move piece
move(move); move(move);
@ -104,13 +107,34 @@ public class Board implements Cloneable {
// TODO: Select promotion // TODO: Select promotion
setDest(move, new Queen(piece.getColor(), this)); setDest(move, new Queen(piece.getColor(), this));
break; 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: case UNKNOWN:
System.err.printf("Unknown move %s found!%n", move); System.err.printf("Move of unknown type %s found!%n", move);
case NORMAL: case NORMAL:
setDest(move, piece); setDest(move, piece);
setPos(move, null); 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 // Update the king's position if the moved piece is the king
if (piece.getType() == Type.KING) kingPos.put(piece.getColor(), move.dest); if (piece.getType() == Type.KING) kingPos.put(piece.getColor(), move.dest);
@ -127,19 +151,38 @@ public class Board implements Cloneable {
Piece capturedPiece = loggedMove.capturedPiece; Piece capturedPiece = loggedMove.capturedPiece;
switch (move.type) { switch (move.type) {
case CASTLING:
case EN_PASSANT:
case PAWN_PROMOTION: case PAWN_PROMOTION:
setPos(move, new Pawn(getDest(move).getColor(), this)); setPos(move, new Pawn(getDest(move).getColor(), this));
setDest(move, capturedPiece); setDest(move, capturedPiece);
break; 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: case UNKNOWN:
System.err.printf("Unknown move %s found!%n", move); System.err.printf("Move of unknown type %s found!%n", move);
case NORMAL: case NORMAL:
setPos(move, getDest(move)); setPos(move, getDest(move));
setDest(move, capturedPiece); 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 // 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); if (getPos(move).getType() == Type.KING) kingPos.put(getPos(move).getColor(), move.pos);

View File

@ -17,7 +17,26 @@ public class King extends Piece {
@Override @Override
public boolean isValidMove(Move move) { 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 @Override
@ -29,9 +48,33 @@ public class King extends Piece {
Move move = new Move(pos, new Position(i, j)); Move move = new Move(pos, new Position(i, j));
if (board.getDest(move) == null || board.getDest(move).getColor() != getColor()) moves.add(move); 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; 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 @Override
public Type getType() { return Type.KING; } public Type getType() { return Type.KING; }
} }

View File

@ -11,8 +11,9 @@ import java.util.List;
*/ */
public abstract class Piece implements Cloneable { public abstract class Piece implements Cloneable {
protected Color color; private final Color color;
protected Board board; protected Board board;
private int moveCounter;
public Piece(Color color, Board board) { public Piece(Color color, Board board) {
this.color = color; this.color = color;
@ -24,8 +25,7 @@ public abstract class Piece implements Cloneable {
for (Iterator<Move> iterator = moves.iterator(); iterator.hasNext();) { for (Iterator<Move> iterator = moves.iterator(); iterator.hasNext();) {
Move move = iterator.next(); Move move = iterator.next();
board.move(move); board.move(move);
if (board.checkCheck(getColor())) if (board.checkCheck(getColor())) iterator.remove();
iterator.remove();
board.revert(); board.revert();
} }
return moves; return moves;
@ -66,6 +66,16 @@ public abstract class Piece implements Cloneable {
public Color getColor() { return color; } public Color getColor() { return color; }
public int getMoveCounter() { return moveCounter; }
public void incMoveCounter() {
++moveCounter;
}
public void decMoveCounter() {
--moveCounter;
}
public static enum Type { public static enum Type {
KING, QUEEN, ROOK, KNIGHT, BISHOP, PAWN KING, QUEEN, ROOK, KNIGHT, BISHOP, PAWN
} }

View File

@ -7,6 +7,7 @@ import java.util.stream.Collectors;
import dev.kske.chess.board.Board; import dev.kske.chess.board.Board;
import dev.kske.chess.board.Move; 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.Piece.Color;
import dev.kske.chess.board.Position; import dev.kske.chess.board.Position;
import dev.kske.chess.ui.OverlayComponent; import dev.kske.chess.ui.OverlayComponent;
@ -49,7 +50,7 @@ public class NaturalPlayer extends Player {
overlayComponent.clearDots(); overlayComponent.clearDots();
moveRequested = false; moveRequested = false;
game.onMove(NaturalPlayer.this, new Move(pos, dest)); game.onMove(NaturalPlayer.this, new Move(pos, dest, Type.UNKNOWN));
pos = null; pos = null;
} }
} }

View File

@ -79,5 +79,7 @@ public class GameModeDialog extends JDialog {
dispose(); dispose();
}); });
getContentPane().add(btnAI2); getContentPane().add(btnAI2);
setLocationRelativeTo(null);
} }
} }

View File

@ -64,6 +64,7 @@ public class MainWindow {
btnRestart.addActionListener((evt) -> System.err.println("Resetting not implemented!")); btnRestart.addActionListener((evt) -> System.err.println("Resetting not implemented!"));
toolPanel.add(btnRestart); toolPanel.add(btnRestart);
mframe.pack(); mframe.pack();
mframe.setLocationRelativeTo(null);
// Display dialog for game mode selection // Display dialog for game mode selection
new GameModeDialog(boardPane).setVisible(true); new GameModeDialog(boardPane).setVisible(true);