Fixed castling, added castling export to FEN
+ isFreePath implementation in Piece - Removed isFreePath from Bishop, Rook, Queen and King + canCastleKingside and canCastleQueenside methods in King + Castling rights record in Board + FEN export + equals method in Position + UCI 'position startpos' command - Switched to Java 8 compliance for compatibility reasons
This commit is contained in:
		| @@ -20,14 +20,6 @@ public class Bishop extends Piece { | ||||
| 		return move.isDiagonal() && isFreePath(move); | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| 	protected boolean isFreePath(Move move) { | ||||
| 		for (int i = move.pos.x + move.xSign, j = move.pos.y | ||||
| 				+ move.ySign; i != move.dest.x; i += move.xSign, j += move.ySign) | ||||
| 			if (board.getBoardArr()[i][j] != null) return false; | ||||
| 		return checkDestination(move); | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| 	protected List<Move> getPseudolegalMoves(Position pos) { | ||||
| 		List<Move> moves = new ArrayList<>(); | ||||
|   | ||||
| @@ -17,10 +17,11 @@ import dev.kske.chess.board.Piece.Type; | ||||
|  */ | ||||
| public class Board implements Cloneable { | ||||
|  | ||||
| 	private Piece[][]				boardArr; | ||||
| 	private Map<Color, Position>	kingPos; | ||||
| 	private Color					activeColor; | ||||
| 	private Log						log; | ||||
| 	private Piece[][]						boardArr; | ||||
| 	private Map<Color, Position>			kingPos; | ||||
| 	private Map<Color, Map<Type, Boolean>>	castlingRights; | ||||
| 	private Color							activeColor; | ||||
| 	private Log								log; | ||||
|  | ||||
| 	private int fullmoveCounter, halfmoveClock; | ||||
|  | ||||
| @@ -62,9 +63,10 @@ public class Board implements Cloneable { | ||||
| 	} | ||||
|  | ||||
| 	public Board() { | ||||
| 		boardArr	= new Piece[8][8]; | ||||
| 		kingPos		= new HashMap<>(); | ||||
| 		log			= new Log(); | ||||
| 		boardArr		= new Piece[8][8]; | ||||
| 		kingPos			= new HashMap<>(); | ||||
| 		castlingRights	= new HashMap<>(); | ||||
| 		log				= new Log(); | ||||
| 		initializeDefaultPositions(); | ||||
| 	} | ||||
|  | ||||
| @@ -140,8 +142,13 @@ public class Board implements Cloneable { | ||||
| 		// 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); | ||||
| 		// Update the king's position if the moved piece is the king and castling | ||||
| 		// availability | ||||
| 		if (piece.getType() == Type.KING) { | ||||
| 			kingPos.put(piece.getColor(), move.dest); | ||||
| 			castlingRights.get(piece.getColor()).put(Type.KING, false); | ||||
| 			castlingRights.get(piece.getColor()).put(Type.QUEEN, false); | ||||
| 		} | ||||
|  | ||||
| 		// Update log | ||||
| 		log.add(move, capturePiece); | ||||
| @@ -154,6 +161,8 @@ public class Board implements Cloneable { | ||||
|  | ||||
| 		// Increment halfmove clock | ||||
| 		++halfmoveClock; | ||||
|  | ||||
| 		updateCastlingRights(); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| @@ -211,6 +220,30 @@ public class Board implements Cloneable { | ||||
|  | ||||
| 		// Decrement halfmove clock | ||||
| 		--halfmoveClock; | ||||
|  | ||||
| 		updateCastlingRights(); | ||||
| 	} | ||||
|  | ||||
| 	private void updateCastlingRights() { | ||||
| 		// White | ||||
| 		if (new Position(4, 7).equals(kingPos.get(Color.WHITE))) { | ||||
| 			final King king = (King) get(kingPos.get(Color.WHITE)); | ||||
| 			castlingRights.get(Color.WHITE).put(Type.KING, king.canCastleKingside()); | ||||
| 			castlingRights.get(Color.WHITE).put(Type.QUEEN, king.canCastleQueenside()); | ||||
| 		} else { | ||||
| 			castlingRights.get(Color.WHITE).put(Type.KING, false); | ||||
| 			castlingRights.get(Color.WHITE).put(Type.QUEEN, false); | ||||
| 		} | ||||
|  | ||||
| 		// Black | ||||
| 		if (new Position(4, 0).equals(kingPos.get(Color.BLACK))) { | ||||
| 			final King king = (King) get(kingPos.get(Color.BLACK)); | ||||
| 			castlingRights.get(Color.BLACK).put(Type.KING, king.canCastleKingside()); | ||||
| 			castlingRights.get(Color.BLACK).put(Type.QUEEN, king.canCastleQueenside()); | ||||
| 		} else { | ||||
| 			castlingRights.get(Color.BLACK).put(Type.KING, false); | ||||
| 			castlingRights.get(Color.BLACK).put(Type.QUEEN, false); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| @@ -354,9 +387,19 @@ public class Board implements Cloneable { | ||||
| 			for (int j = 2; j < 6; j++) | ||||
| 				boardArr[i][j] = null; | ||||
|  | ||||
| 		// Initialize castling rights | ||||
| 		castlingRights.clear(); | ||||
| 		Map<Type, Boolean> whiteCastling = new HashMap<>(), blackCastling = new HashMap<>(); | ||||
| 		whiteCastling.put(Type.KING, true); | ||||
| 		whiteCastling.put(Type.QUEEN, true); | ||||
| 		blackCastling.put(Type.KING, true); | ||||
| 		blackCastling.put(Type.QUEEN, true); | ||||
| 		castlingRights.put(Color.WHITE, whiteCastling); | ||||
| 		castlingRights.put(Color.BLACK, blackCastling); | ||||
|  | ||||
| 		activeColor = Color.WHITE; | ||||
| 		 | ||||
| 		fullmoveCounter = 1; | ||||
|  | ||||
| 		fullmoveCounter	= 1; | ||||
| 		halfmoveClock	= 0; | ||||
| 	} | ||||
|  | ||||
| @@ -437,8 +480,14 @@ public class Board implements Cloneable { | ||||
| 		// Active color | ||||
| 		sb.append(" " + (activeColor == Color.WHITE ? 'w' : 'b')); | ||||
|  | ||||
| 		// TODO: castling rights | ||||
| 		sb.append(" -"); | ||||
| 		sb.append(' '); | ||||
| 		StringBuilder castlingSb = new StringBuilder(); | ||||
| 		if (castlingRights.get(Color.WHITE).get(Type.KING)) castlingSb.append('K'); | ||||
| 		if (castlingRights.get(Color.WHITE).get(Type.QUEEN)) castlingSb.append('Q'); | ||||
| 		if (castlingRights.get(Color.BLACK).get(Type.KING)) castlingSb.append('k'); | ||||
| 		if (castlingRights.get(Color.BLACK).get(Type.QUEEN)) castlingSb.append('q'); | ||||
| 		if (castlingSb.length() == 0) sb.append("-"); | ||||
| 		sb.append(castlingSb); | ||||
|  | ||||
| 		// TODO: en passant availability | ||||
| 		sb.append(" -"); | ||||
| @@ -481,5 +530,8 @@ public class Board implements Cloneable { | ||||
| 	 */ | ||||
| 	public Piece[][] getBoardArr() { return boardArr; } | ||||
|  | ||||
| 	/** | ||||
| 	 * @return The active color for the next move | ||||
| 	 */ | ||||
| 	public Color getActiveColor() { return activeColor; } | ||||
| } | ||||
|   | ||||
| @@ -18,27 +18,40 @@ public class King extends Piece { | ||||
| 	@Override | ||||
| 	public boolean isValidMove(Move 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)))) { | ||||
| 		if (move.xDist == 2 && move.yDist == 0) { | ||||
| 			if (canCastleKingside()) { | ||||
| 				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)))) { | ||||
| 			if (canCastleQueenside()) { | ||||
| 				move.type = Move.Type.CASTLING; | ||||
| 				return true; | ||||
| 			} | ||||
|  | ||||
| 		} | ||||
|  | ||||
| 		return move.xDist <= 1 && move.yDist <= 1 && checkDestination(move); | ||||
| 	} | ||||
|  | ||||
| 	public boolean canCastleKingside() { | ||||
| 		if (getMoveCounter() == 0) { | ||||
| 			int			y		= getColor() == Color.WHITE ? 7 : 0; | ||||
| 			Position	rookPos	= new Position(7, y); | ||||
| 			Piece		rook	= board.get(rookPos); | ||||
| 			return rook != null && rook.getType() == Type.ROOK && rook.getMoveCounter() == 0 | ||||
| 					&& isFreePath(new Move(new Position(4, y), new Position(6, y))); | ||||
| 		} else return false; | ||||
| 	} | ||||
|  | ||||
| 	public boolean canCastleQueenside() { | ||||
| 		if (getMoveCounter() == 0) { | ||||
| 			int			y		= getColor() == Color.WHITE ? 7 : 0; | ||||
| 			Position	rookPos	= new Position(0, y); | ||||
| 			Piece		rook	= board.get(rookPos); | ||||
| 			return rook != null && rook.getType() == Type.ROOK && rook.getMoveCounter() == 0 | ||||
| 					&& isFreePath(new Move(new Position(4, y), new Position(1, y))); | ||||
| 		} else return false; | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| 	protected List<Move> getPseudolegalMoves(Position pos) { | ||||
| 		List<Move> moves = new ArrayList<>(); | ||||
| @@ -50,31 +63,13 @@ public class King extends Piece { | ||||
| 				} | ||||
|  | ||||
| 		// 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)); | ||||
| 		} | ||||
| 		// TODO: Condition: cannot castle out of, through or into check | ||||
| 		if (canCastleKingside()) moves.add(new Move(pos, new Position(6, pos.y), Move.Type.CASTLING)); | ||||
| 		if (canCastleQueenside()) 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; } | ||||
| } | ||||
|   | ||||
| @@ -35,8 +35,16 @@ public abstract class Piece implements Cloneable { | ||||
|  | ||||
| 	public abstract boolean isValidMove(Move move); | ||||
|  | ||||
| 	/** | ||||
| 	 * Checks, if the squares between the position and the destination of a move are | ||||
| 	 * free. | ||||
| 	 *  | ||||
| 	 * @param move The move to check | ||||
| 	 */ | ||||
| 	protected boolean isFreePath(Move move) { | ||||
| 		// Only check destination by default | ||||
| 		for (int i = move.pos.x + move.xSign, j = move.pos.y + move.ySign; i != move.dest.x | ||||
| 				|| j != move.dest.y; i += move.xSign, j += move.ySign) | ||||
| 			if (board.getBoardArr()[i][j] != null) return false; | ||||
| 		return checkDestination(move); | ||||
| 	} | ||||
|  | ||||
|   | ||||
| @@ -23,4 +23,24 @@ public class Position { | ||||
| 	public String toString() { | ||||
| 		return String.format("[%d, %d]", x, y); | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| 	public int hashCode() { | ||||
| 		final int	prime	= 31; | ||||
| 		int			result	= 1; | ||||
| 		result	= prime * result + x; | ||||
| 		result	= prime * result + y; | ||||
| 		return result; | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| 	public boolean equals(Object obj) { | ||||
| 		if (this == obj) return true; | ||||
| 		if (obj == null) return false; | ||||
| 		if (getClass() != obj.getClass()) return false; | ||||
| 		Position other = (Position) obj; | ||||
| 		if (x != other.x) return false; | ||||
| 		if (y != other.y) return false; | ||||
| 		return true; | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -20,22 +20,6 @@ public class Queen extends Piece { | ||||
| 		return ((move.isHorizontal() || move.isVertical()) || move.isDiagonal()) && isFreePath(move); | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| 	protected boolean isFreePath(Move move) { | ||||
| 		if (move.isHorizontal()) { | ||||
| 			for (int i = move.pos.x + move.xSign; i != move.dest.x; i += move.xSign) | ||||
| 				if (board.getBoardArr()[i][move.pos.y] != null) return false; | ||||
| 		} else if (move.isVertical()) { | ||||
| 			for (int i = move.pos.y + move.ySign; i != move.dest.y; i += move.ySign) | ||||
| 				if (board.getBoardArr()[move.pos.x][i] != null) return false; | ||||
| 		} else { | ||||
| 			for (int i = move.pos.x + move.xSign, j = move.pos.y | ||||
| 					+ move.ySign; i != move.dest.x; i += move.xSign, j += move.ySign) | ||||
| 				if (board.getBoardArr()[i][j] != null) return false; | ||||
| 		} | ||||
| 		return checkDestination(move); | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| 	protected List<Move> getPseudolegalMoves(Position pos) { | ||||
| 		List<Move> moves = new ArrayList<>(); | ||||
|   | ||||
| @@ -20,18 +20,6 @@ public class Rook extends Piece { | ||||
| 		return (move.isHorizontal() || move.isVertical()) && isFreePath(move); | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| 	protected boolean isFreePath(Move move) { | ||||
| 		if (move.isHorizontal()) { | ||||
| 			for (int i = move.pos.x + move.xSign; i != move.dest.x; i += move.xSign) | ||||
| 				if (board.getBoardArr()[i][move.pos.y] != null) return false; | ||||
| 		} else { | ||||
| 			for (int i = move.pos.y + move.ySign; i != move.dest.y; i += move.ySign) | ||||
| 				if (board.getBoardArr()[move.pos.x][i] != null) return false; | ||||
| 		} | ||||
| 		return checkDestination(move); | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| 	protected List<Move> getPseudolegalMoves(Position pos) { | ||||
| 		List<Move> moves = new ArrayList<>(); | ||||
|   | ||||
| @@ -94,6 +94,13 @@ public class UCIHandle { | ||||
|  | ||||
| 	// TODO: position | ||||
|  | ||||
| 	/** | ||||
| 	 * Sets up the position in its initial state. | ||||
| 	 */ | ||||
| 	public void startPosition() { | ||||
| 		out.println("position startpos"); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Sets up the position described in the FEN string. | ||||
| 	 *  | ||||
|   | ||||
| @@ -32,7 +32,7 @@ public class UCIReceiver implements Runnable { | ||||
| 		String line; | ||||
| 		while (!Thread.currentThread().isInterrupted()) | ||||
| 			try { | ||||
| 				if ((line = in.readLine()) != null && !line.isBlank()) parse(line); | ||||
| 				if ((line = in.readLine()) != null && !line.isEmpty()) parse(line); | ||||
| 			} catch (IndexOutOfBoundsException ex) { | ||||
| 				System.err.println("Too few arguments were provided!"); | ||||
| 				ex.printStackTrace(); | ||||
|   | ||||
							
								
								
									
										54
									
								
								src/dev/kske/chess/ui/LogFrame.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								src/dev/kske/chess/ui/LogFrame.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,54 @@ | ||||
| package dev.kske.chess.ui; | ||||
|  | ||||
| import java.awt.BorderLayout; | ||||
|  | ||||
| import javax.swing.JFrame; | ||||
| import javax.swing.JPanel; | ||||
| import javax.swing.JTable; | ||||
| import javax.swing.border.EmptyBorder; | ||||
| import javax.swing.table.DefaultTableModel; | ||||
|  | ||||
| import dev.kske.chess.board.Log; | ||||
|  | ||||
| /** | ||||
|  * Project: <strong>Chess</strong><br> | ||||
|  * File: <strong>LogFrame.java</strong><br> | ||||
|  * Created: <strong>17.07.2019</strong><br> | ||||
|  * Author: <strong>Kai S. K. Engelbart</strong> | ||||
|  */ | ||||
| public class LogFrame extends JFrame { | ||||
|  | ||||
| 	private static final long serialVersionUID = 1932671698254197119L; | ||||
|  | ||||
| 	private JPanel	mcontentPane; | ||||
| 	private JTable	mtable; | ||||
|  | ||||
| 	private Log log; | ||||
|  | ||||
| 	/** | ||||
| 	 * Create the frame. | ||||
| 	 */ | ||||
| 	public LogFrame() { | ||||
| 		setTitle("Move History"); | ||||
| 		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); | ||||
| 		setBounds(100, 100, 450, 300); | ||||
| 		mcontentPane = new JPanel(); | ||||
| 		mcontentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); | ||||
| 		mcontentPane.setLayout(new BorderLayout(0, 0)); | ||||
| 		setContentPane(mcontentPane); | ||||
|  | ||||
| 		mtable = new JTable(); | ||||
| 		mtable.setModel(new DefaultTableModel(new Object[][] {}, new String[] { "Black", "New column" })); | ||||
| 		mtable.setEnabled(false); | ||||
| 		mcontentPane.add(mtable, BorderLayout.CENTER); | ||||
| 	} | ||||
|  | ||||
| 	public void update() { | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	public Log getLog() { return log; } | ||||
|  | ||||
| 	public void setLog(Log log) { this.log = log; } | ||||
|  | ||||
| } | ||||
		Reference in New Issue
	
	Block a user