diff --git a/src/dev/kske/chess/board/Board.java b/src/dev/kske/chess/board/Board.java index 3288e2b..114f32e 100644 --- a/src/dev/kske/chess/board/Board.java +++ b/src/dev/kske/chess/board/Board.java @@ -13,7 +13,7 @@ import dev.kske.chess.board.Piece.Color; * Project: Chess
* File: Board.java
* Created: 01.07.2019
- * + * * @since Chess v0.1-alpha * @author Kai S. K. Engelbart */ @@ -32,11 +32,11 @@ public class Board { * Creates a copy of another {@link Board} instance.
* The created object is a deep copy, but does not contain any move history * apart from the current {@link MoveNode}. - * + * * @param other The {@link Board} instance to copy + * @param copyVariations TODO */ - public Board(Board other) { - boardArr = new Piece[8][8]; + public Board(Board other, boolean copyVariations) { for (int i = 0; i < 8; i++) for (int j = 0; j < 8; j++) { if (other.boardArr[i][j] == null) continue; @@ -45,12 +45,16 @@ public class Board { } kingPos.putAll(other.kingPos); - log = new Log(other.log, false); + log = new Log(other.log, copyVariations); + + // Synchronize the current move node with the board + while (log.getLast().hasVariations()) + log.selectNextNode(0); } /** * Moves a piece across the board if the move is legal. - * + * * @param move The move to execute * @return {@code true}, if the attempted move was legal and thus executed */ @@ -73,7 +77,7 @@ public class Board { /** * Moves a piece across the board without checking if the move is legal. - * + * * @param move The move to execute */ public void move(Move move) { @@ -92,7 +96,7 @@ public class Board { /** * Moves a piece across the board without checking if the move is legal. - * + * * @param sanMove The move to execute in SAN (Standard Algebraic Notation) */ public void move(String sanMove) { @@ -118,7 +122,7 @@ public class Board { /** * Generated every legal move for one color - * + * * @param color The color to generate the moves for * @return A list of all legal moves */ @@ -134,7 +138,7 @@ public class Board { /** * Checks, if the king is in check. - * + * * @param color The color of the king to check * @return {@code true}, if the king is in check */ @@ -142,7 +146,7 @@ public class Board { /** * Checks, if a field can be attacked by pieces of a certain color. - * + * * @param dest the field to check * @param color the color of a potential attacker piece * @return {@code true} if a move with the destination {@code dest} @@ -159,7 +163,7 @@ public class Board { /** * Checks, if the king is in checkmate. * This requires the king to already be in check! - * + * * @param color The color of the king to check * @return {@code true}, if the king is in checkmate */ @@ -256,7 +260,7 @@ public class Board { /** * Searches for a {@link Piece} inside a file (A - H). - * + * * @param pieceClass The class of the piece to search for * @param file The file in which to search for the piece * @return The rank (1 - 8) of the first piece with the specified type and @@ -271,7 +275,7 @@ public class Board { /** * Searches for a {@link Piece} inside a rank (1 - 8). - * + * * @param pieceClass The class of the piece to search for * @param rank The rank in which to search for the piece * @return The file (A - H) of the first piece with the specified type and @@ -287,7 +291,7 @@ public class Board { /** * Searches for a {@link Piece} that can move to a {@link Position}. - * + * * @param pieceClass The class of the piece to search for * @param dest The destination that the piece is required to reach * @return The position of a piece that can move to the specified destination @@ -304,7 +308,7 @@ public class Board { /** * Places a piece at a position. - * + * * @param pos The position to place the piece at * @param piece The piece to place */ @@ -324,7 +328,7 @@ public class Board { /** * Places a piece at the position of a move. - * + * * @param move The move at which position to place the piece * @param piece The piece to place */ @@ -332,7 +336,7 @@ public class Board { /** * Places a piece at the destination of a move. - * + * * @param move The move at which destination to place the piece * @param piece The piece to place */ diff --git a/src/dev/kske/chess/board/Log.java b/src/dev/kske/chess/board/Log.java index 95b1433..d8421e4 100644 --- a/src/dev/kske/chess/board/Log.java +++ b/src/dev/kske/chess/board/Log.java @@ -10,7 +10,7 @@ import dev.kske.chess.board.Piece.Color; * Project: Chess
* File: Log.java
* Created: 09.07.2019
- * + * * @since Chess v0.1-alpha * @author Kai S. K. Engelbart */ @@ -28,7 +28,7 @@ public class Log implements Iterable { /** * Creates a (partially deep) copy of another {@link Log} instance which begins * with the current {@link MoveNode}. - * + * * @param other The {@link Log} instance to copy * @param copyVariations If set to {@code true}, subsequent variations of the * current {@link MoveNode} are copied with the @@ -43,7 +43,7 @@ public class Log implements Iterable { // The new root is the current node of the copied instance if (!other.isEmpty()) { - root = new MoveNode(other.current, copyVariations); + root = new MoveNode(other.root, copyVariations); root.setParent(null); current = root; } @@ -76,7 +76,7 @@ public class Log implements Iterable { /** * Adds a move to the move history and adjusts the log to the new position. - * + * * @param move The move to log * @param piece The piece that performed the move * @param capturedPiece The piece captured with the move @@ -140,7 +140,7 @@ public class Log implements Iterable { /** * Changes the current node to one of its children (variations). - * + * * @param index the index of the variation to select */ public void selectNextNode(int index) { @@ -186,7 +186,7 @@ public class Log implements Iterable { * Removed the castling rights bound to a rook or king for the rest of the game. * This method should be called once the piece has been moved, as a castling * move involving this piece is forbidden afterwards. - * + * * @param piece the rook or king to disable the castling rights for * @param initialPosition the initial position of the piece during the start of * the game @@ -244,7 +244,7 @@ public class Log implements Iterable { public int getFullmoveNumber() { return fullmoveNumber; } - public void setFullmoveNumber(int fullmoveCounter) { this.fullmoveNumber = fullmoveCounter; } + public void setFullmoveNumber(int fullmoveCounter) { fullmoveNumber = fullmoveCounter; } public int getHalfmoveClock() { return halfmoveClock; } diff --git a/src/dev/kske/chess/board/Move.java b/src/dev/kske/chess/board/Move.java index d3841c8..2ff63e2 100644 --- a/src/dev/kske/chess/board/Move.java +++ b/src/dev/kske/chess/board/Move.java @@ -157,8 +157,8 @@ public class Move { // Position // TODO: Deconstruct position into optional file or rank - // TODO: Omit if the move is a pawn push - sb.append(pos.toLAN()); + // Omit position if the move is a pawn push + if (!(piece instanceof Pawn && xDist == 0)) sb.append(pos.toLAN()); // Capture indicator if (board.get(dest) != null) sb.append('x'); diff --git a/src/dev/kske/chess/board/MoveNode.java b/src/dev/kske/chess/board/MoveNode.java index a8bf2b8..e618716 100644 --- a/src/dev/kske/chess/board/MoveNode.java +++ b/src/dev/kske/chess/board/MoveNode.java @@ -11,7 +11,7 @@ import dev.kske.chess.board.Piece.Color; * Project: Chess
* File: MoveNode.java
* Created: 02.10.2019
- * + * * @since Chess v0.5-alpha * @author Kai S. K. Engelbart */ @@ -31,7 +31,7 @@ public class MoveNode { /** * Creates a new {@link MoveNode}. - * + * * @param move The logged {@link Move} * @param capturedPiece The {@link Piece} captures by the logged {@link Move} * @param enPassant The en passant {@link Position} valid after the logged @@ -53,7 +53,7 @@ public class MoveNode { /** * Creates a (deep) copy of another {@link MoveNode}. - * + * * @param other The {@link MoveNode} to copy * @param copyVariations When this is set to {@code true} a deep copy is * created, which @@ -64,17 +64,17 @@ public class MoveNode { other.fullmoveCounter, other.halfmoveClock); if (copyVariations && other.variations != null) { if (variations == null) variations = new ArrayList<>(); - other.variations.forEach(variation -> { + for (MoveNode variation : other.variations) { MoveNode copy = new MoveNode(variation, true); copy.parent = this; variations.add(copy); - }); + } } } /** * Adds another {@link MoveNode} as a child node. - * + * * @param variation The {@link MoveNode} to append to this {@link MoveNode} */ public void addVariation(MoveNode variation) { diff --git a/src/dev/kske/chess/game/ai/AIPlayer.java b/src/dev/kske/chess/game/ai/AIPlayer.java index 7e8c015..9e53326 100644 --- a/src/dev/kske/chess/game/ai/AIPlayer.java +++ b/src/dev/kske/chess/game/ai/AIPlayer.java @@ -52,7 +52,7 @@ public class AIPlayer extends Player { /* * Get a copy of the board and the available moves. */ - Board board = new Board(this.board); + Board board = new Board(this.board, false); List moves = board.getMoves(color); /* @@ -66,7 +66,7 @@ public class AIPlayer extends Player { for (int i = 0; i < numThreads; i++) { if (rem-- > 0) ++endIndex; endIndex += step; - processors.add(new MoveProcessor(new Board(board), moves.subList(beginIndex, endIndex), color, + processors.add(new MoveProcessor(new Board(board, false), moves.subList(beginIndex, endIndex), color, maxDepth, alphaBetaThreshold)); beginIndex = endIndex; } diff --git a/src/dev/kske/chess/pgn/PGNGame.java b/src/dev/kske/chess/pgn/PGNGame.java index 5d443c8..9308b47 100644 --- a/src/dev/kske/chess/pgn/PGNGame.java +++ b/src/dev/kske/chess/pgn/PGNGame.java @@ -1,7 +1,9 @@ package dev.kske.chess.pgn; import java.io.PrintWriter; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Scanner; import java.util.regex.MatchResult; @@ -9,14 +11,14 @@ import java.util.regex.Pattern; import dev.kske.chess.board.Board; import dev.kske.chess.board.FENString; -import dev.kske.chess.board.Piece.Color; +import dev.kske.chess.board.Move; import dev.kske.chess.exception.ChessException; /** * Project: Chess
* File: PGNGame.java
* Created: 22 Sep 2019
- * + * * @since Chess v0.5-alpha * @author Kai S. K. Engelbart */ @@ -78,11 +80,25 @@ public class PGNGame { // Insert newline if tags were printed if (!tagPairs.isEmpty()) pw.println(); + // Collect SAN moves + Board clone = new Board(board, true); + List sanMoves = new ArrayList<>(); + + while (clone.getLog().hasParent()) { + Move move = clone.getLog().getLast().move; + clone.revert(); + sanMoves.add(move.toSAN(clone)); + } + // Write movetext - board.getLog().forEach(m -> { - if (m.activeColor == Color.BLACK) pw.printf("%d. ", m.fullmoveCounter); - pw.printf("%s ", m.move); // TODO: Convert to SAN - }); + for (int i = sanMoves.size() - 1; i >= 0; i--) + pw.printf("%s ", sanMoves.get(i)); + + // Write movetext + // board.getLog().forEach(m -> { + // if (m.activeColor == Color.BLACK) pw.printf("%d. ", m.fullmoveCounter); + // pw.printf("%s ", m.move.toSAN(board)); + // }); // Write game termination marker pw.print(tagPairs.get("Result")); diff --git a/src/dev/kske/chess/ui/DialogUtil.java b/src/dev/kske/chess/ui/DialogUtil.java index 5c884b5..0621666 100644 --- a/src/dev/kske/chess/ui/DialogUtil.java +++ b/src/dev/kske/chess/ui/DialogUtil.java @@ -24,7 +24,7 @@ import dev.kske.chess.io.EngineUtil; * Project: Chess
* File: DialogUtil.java
* Created: 24.07.2019
- * + * * @since Chess v0.3-alpha * @author Kai S. K. Engelbart */ @@ -62,7 +62,7 @@ public class DialogUtil { dialogPanel.add(lblWhite); JComboBox cbWhite = new JComboBox<>(); - cbWhite.setModel(new DefaultComboBoxModel(options.toArray())); + cbWhite.setModel(new DefaultComboBoxModel<>(options.toArray())); cbWhite.setBounds(98, 9, 159, 22); dialogPanel.add(cbWhite); @@ -72,7 +72,7 @@ public class DialogUtil { dialogPanel.add(lblBlack); JComboBox cbBlack = new JComboBox<>(); - cbBlack.setModel(new DefaultComboBoxModel(options.toArray())); + cbBlack.setModel(new DefaultComboBoxModel<>(options.toArray())); cbBlack.setBounds(98, 36, 159, 22); dialogPanel.add(cbBlack); diff --git a/test/dev/kske/chess/board/BoardTest.java b/test/dev/kske/chess/board/BoardTest.java index b647632..776d221 100644 --- a/test/dev/kske/chess/board/BoardTest.java +++ b/test/dev/kske/chess/board/BoardTest.java @@ -31,7 +31,7 @@ class BoardTest { */ @Test void testClone() { - Board clone = new Board(board); + Board clone = new Board(board, false); assertNotSame(clone, board); assertNotSame(clone.getBoardArr(), board.getBoardArr());