Added castling, fixed some minor bugs
This commit is contained in:
		| @@ -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); | ||||
|  | ||||
|   | ||||
| @@ -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; } | ||||
| } | ||||
|   | ||||
| @@ -11,8 +11,9 @@ import java.util.List; | ||||
|  */ | ||||
| public abstract class Piece implements Cloneable { | ||||
|  | ||||
| 	protected Color	color; | ||||
| 	private final Color	color; | ||||
| 	protected Board		board; | ||||
| 	private int			moveCounter; | ||||
|  | ||||
| 	public Piece(Color color, Board board) { | ||||
| 		this.color	= color; | ||||
| @@ -24,8 +25,7 @@ public abstract class Piece implements Cloneable { | ||||
| 		for (Iterator<Move> iterator = moves.iterator(); iterator.hasNext();) { | ||||
| 			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 | ||||
| 	} | ||||
|   | ||||
| @@ -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; | ||||
| 				} | ||||
| 			} | ||||
|   | ||||
| @@ -79,5 +79,7 @@ public class GameModeDialog extends JDialog { | ||||
| 			dispose(); | ||||
| 		}); | ||||
| 		getContentPane().add(btnAI2); | ||||
|  | ||||
| 		setLocationRelativeTo(null); | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -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); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user