feat: pgn parser
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -8,4 +8,5 @@ app/bin
|
||||
|
||||
.vscode
|
||||
|
||||
audio/*.wav
|
||||
audio/*.wav
|
||||
app/audio/*.wav
|
||||
@@ -43,16 +43,20 @@ run {
|
||||
standardInput = System.in
|
||||
}
|
||||
|
||||
|
||||
// Apply a specific Java toolchain to ease working on different environments.
|
||||
java {
|
||||
toolchain {
|
||||
languageVersion = JavaLanguageVersion.of(21)
|
||||
}
|
||||
}
|
||||
|
||||
jar {
|
||||
manifest {
|
||||
attributes 'Main-Class': application.mainClass
|
||||
}
|
||||
}
|
||||
|
||||
run {
|
||||
standardInput = System.in
|
||||
}
|
||||
|
||||
tasks.named('test') {
|
||||
// Use JUnit Platform for unit tests.
|
||||
useJUnitPlatform()
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package chess.controller;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import chess.controller.Command.CommandResult;
|
||||
import chess.controller.commands.UndoCommand;
|
||||
import chess.controller.event.AsyncGameDispatcher;
|
||||
@@ -42,6 +44,13 @@ public class CommandExecutor {
|
||||
return result;
|
||||
}
|
||||
|
||||
public void executeCommands(List<? extends Command> commands) {
|
||||
for (Command command : commands) {
|
||||
CommandResult result = executeCommand(command);
|
||||
assert result != CommandResult.NotAllowed;
|
||||
}
|
||||
}
|
||||
|
||||
private void processResult(Command command, CommandResult result) {
|
||||
switch (result) {
|
||||
case NotAllowed:
|
||||
|
||||
@@ -112,21 +112,33 @@ public class ChessBoard {
|
||||
}
|
||||
|
||||
public Coordinate findKing(Color color) {
|
||||
// KingIdentifier kingIdentifier = new KingIdentifier(color);
|
||||
// for (int i = 0; i < Coordinate.VALUE_MAX; i++) {
|
||||
// for (int j = 0; j < Coordinate.VALUE_MAX; j++) {
|
||||
// Coordinate coordinate = new Coordinate(i, j);
|
||||
// Piece piece = pieceAt(coordinate);
|
||||
// if (kingIdentifier.isKing(piece)) {
|
||||
// return coordinate;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// assert false : "No king found ?!";
|
||||
// return null;
|
||||
return kingPos[color.ordinal()];
|
||||
}
|
||||
|
||||
public List<Coordinate> getAllowedStarts(Coordinate finish, Color color) {
|
||||
List<Coordinate> starts = new ArrayList<>();
|
||||
for (int i = 0; i < Coordinate.VALUE_MAX; i++) {
|
||||
for (int j = 0; j < Coordinate.VALUE_MAX; j++) {
|
||||
Coordinate attackCoords = new Coordinate(i, j);
|
||||
Piece attackPiece = pieceAt(attackCoords);
|
||||
if (attackPiece == null || attackPiece.getColor() != color)
|
||||
continue;
|
||||
|
||||
Move move = new Move(attackCoords, finish);
|
||||
PiecePathChecker piecePathChecker = new PiecePathChecker(this,
|
||||
move);
|
||||
if (!piecePathChecker.isValid())
|
||||
continue;
|
||||
|
||||
applyMove(move);
|
||||
if (!isKingInCheck(color))
|
||||
starts.add(attackCoords);
|
||||
undoLastMove();
|
||||
}
|
||||
}
|
||||
return starts;
|
||||
}
|
||||
|
||||
public boolean isKingInCheck(Color color) {
|
||||
Coordinate kingPos = findKing(color);
|
||||
assert kingPos.isValid() : "King position is invalid!";
|
||||
|
||||
@@ -4,6 +4,7 @@ import java.util.List;
|
||||
|
||||
import chess.controller.CommandExecutor;
|
||||
import chess.controller.PlayerCommand;
|
||||
import chess.controller.Command.CommandResult;
|
||||
import chess.controller.commands.CastlingCommand;
|
||||
import chess.controller.commands.GetPieceAtCommand;
|
||||
import chess.controller.commands.GetPlayerMovesCommand;
|
||||
@@ -88,7 +89,7 @@ public class PgnExport {
|
||||
Piece otherPiece = pieceAt(cmdExec, move.getStart());
|
||||
|
||||
// checking type of piece
|
||||
if (otherPiece.hashCode() != movingPiece.hashCode())
|
||||
if (!otherPiece.getClass().equals(movingPiece.getClass()))
|
||||
continue;
|
||||
|
||||
String startPos = toString(pieceMove.getStart());
|
||||
@@ -149,7 +150,10 @@ public class PgnExport {
|
||||
}
|
||||
}
|
||||
|
||||
private static String printMove(PlayerCommand cmd, PlayerCommand nextCommand, Game virtualGame,
|
||||
private record MoveResult(String move, CommandResult commandResult) {
|
||||
}
|
||||
|
||||
private static MoveResult printMove(PlayerCommand cmd, PlayerCommand nextCommand, Game virtualGame,
|
||||
CommandExecutor executor) {
|
||||
String result = "";
|
||||
if (cmd instanceof MoveCommand move) {
|
||||
@@ -177,14 +181,14 @@ public class PgnExport {
|
||||
result += castling(castlingCommand);
|
||||
}
|
||||
|
||||
executor.executeCommand(cmd);
|
||||
CommandResult commandResult = executor.executeCommand(cmd);
|
||||
|
||||
// check or checkmate
|
||||
result += checkCheckMate(virtualGame);
|
||||
|
||||
result += " ";
|
||||
|
||||
return result;
|
||||
return new MoveResult(result, commandResult);
|
||||
}
|
||||
|
||||
public static String exportGame(Game game) {
|
||||
@@ -199,17 +203,33 @@ public class PgnExport {
|
||||
|
||||
int tour = 1;
|
||||
|
||||
String lastMove = null;
|
||||
|
||||
for (int i = 0; i < commands.size(); i++) {
|
||||
PlayerCommand cmd = commands.get(i);
|
||||
PlayerCommand nextCommand = null;
|
||||
|
||||
if (i != commands.size() - 1) {
|
||||
nextCommand = commands.get(i + 1);
|
||||
}
|
||||
if (virtualGame.getPlayerTurn() == Color.White) {
|
||||
MoveResult moveResult = printMove(cmd, nextCommand, virtualGame, executor);
|
||||
if (moveResult.commandResult() == CommandResult.Moved && virtualGame.getPlayerTurn() == Color.Black) {
|
||||
result += tour + ".";
|
||||
tour++;
|
||||
}
|
||||
result += printMove(cmd, nextCommand, virtualGame, executor);
|
||||
|
||||
if (moveResult.commandResult() == CommandResult.ActionNeeded) {
|
||||
lastMove = moveResult.move();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (lastMove != null && moveResult.commandResult() == CommandResult.Moved){
|
||||
result += lastMove;
|
||||
lastMove = null;
|
||||
continue;
|
||||
}
|
||||
result += moveResult.move();
|
||||
|
||||
}
|
||||
return result + " " + gameEnd(virtualGame);
|
||||
}
|
||||
|
||||
22
app/src/main/java/chess/pgn/PgnFileSimulator.java
Normal file
22
app/src/main/java/chess/pgn/PgnFileSimulator.java
Normal file
@@ -0,0 +1,22 @@
|
||||
package chess.pgn;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStreamReader;
|
||||
|
||||
import chess.controller.CommandExecutor;
|
||||
import chess.view.AssetManager;
|
||||
|
||||
public class PgnFileSimulator extends PgnSimulator{
|
||||
|
||||
private static String readResource(String path) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(AssetManager.getResource(path)));
|
||||
reader.lines().forEach((line) -> builder.append(line + "\n"));
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
public PgnFileSimulator(CommandExecutor commandExecutor, String fileName) {
|
||||
super(commandExecutor, readResource(fileName));
|
||||
}
|
||||
|
||||
}
|
||||
172
app/src/main/java/chess/pgn/PgnImport.java
Normal file
172
app/src/main/java/chess/pgn/PgnImport.java
Normal file
@@ -0,0 +1,172 @@
|
||||
package chess.pgn;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import chess.controller.CommandExecutor;
|
||||
import chess.controller.PlayerCommand;
|
||||
import chess.controller.commands.CastlingCommand;
|
||||
import chess.controller.commands.MoveCommand;
|
||||
import chess.controller.commands.NewGameCommand;
|
||||
import chess.controller.commands.PromoteCommand;
|
||||
import chess.controller.commands.PromoteCommand.PromoteType;
|
||||
import chess.controller.event.EmptyGameDispatcher;
|
||||
import chess.model.ChessBoard;
|
||||
import chess.model.Coordinate;
|
||||
import chess.model.Game;
|
||||
import chess.model.Move;
|
||||
import chess.model.Piece;
|
||||
import chess.model.pieces.Bishop;
|
||||
import chess.model.pieces.King;
|
||||
import chess.model.pieces.Knight;
|
||||
import chess.model.pieces.Pawn;
|
||||
import chess.model.pieces.Queen;
|
||||
import chess.model.pieces.Rook;
|
||||
|
||||
public class PgnImport {
|
||||
|
||||
private static final Map<String, Class<? extends Piece>> pieceMap = Map.of(
|
||||
"K", King.class,
|
||||
"Q", Queen.class,
|
||||
"R", Rook.class,
|
||||
"B", Bishop.class,
|
||||
"N", Knight.class);
|
||||
|
||||
private static final Map<String, PromoteType> promoteMap = Map.of(
|
||||
"Q", PromoteType.Queen,
|
||||
"R", PromoteType.Rook,
|
||||
"B", PromoteType.Bishop,
|
||||
"N", PromoteType.Knight);
|
||||
|
||||
public static List<PlayerCommand> importGame(String pgnContent) {
|
||||
String[] parts = pgnContent.split("\n\n");
|
||||
// we just ignore headers
|
||||
return getMoves(parts[parts.length - 1]);
|
||||
}
|
||||
|
||||
private static List<PlayerCommand> getMoves(String unparsedMoves) {
|
||||
String[] moves = unparsedMoves.replaceAll("\\{.*?\\}", "") // Remove comments
|
||||
.replaceAll("\\n", " ") // Remove new lines
|
||||
.split("[\\s.]+"); // Split by whitespace and dots (trimming it also)
|
||||
|
||||
Game virtualGame = new Game();
|
||||
CommandExecutor commandExecutor = new CommandExecutor(virtualGame, new EmptyGameDispatcher());
|
||||
List<PlayerCommand> instructions = new ArrayList<>();
|
||||
|
||||
commandExecutor.executeCommand(new NewGameCommand());
|
||||
|
||||
for (int i = 0; i < moves.length; i++) {
|
||||
if (i % 3 == 0)
|
||||
continue;
|
||||
|
||||
String move = moves[i];
|
||||
|
||||
if (move.equals("1-0") || move.equals("0-1") || move.equals("1/2-1/2")) {
|
||||
break; // End of the game
|
||||
}
|
||||
|
||||
List<PlayerCommand> cmds = parseMove(move, virtualGame);
|
||||
commandExecutor.executeCommands(cmds);
|
||||
|
||||
instructions.addAll(cmds);
|
||||
}
|
||||
return instructions;
|
||||
}
|
||||
|
||||
private static List<PlayerCommand> parseMove(String move, Game game) {
|
||||
if (move.equals("O-O-O"))
|
||||
return Arrays.asList(new CastlingCommand(true));
|
||||
if (move.equals("O-O"))
|
||||
return Arrays.asList(new CastlingCommand(false));
|
||||
|
||||
move = move.replaceAll("[x|#|\\+]", "");
|
||||
|
||||
PromoteCommand promoteCommand = null;
|
||||
|
||||
if (move.contains("=")) {
|
||||
String promoteString = move.substring(move.length() - 1);
|
||||
promoteCommand = new PromoteCommand(promoteMap.get(promoteString));
|
||||
move = move.substring(0, move.length() - 2);
|
||||
}
|
||||
|
||||
Class<? extends Piece> pieceType = pieceMap.get(move.substring(0, 1));
|
||||
|
||||
if (pieceType == null)
|
||||
pieceType = Pawn.class;
|
||||
else
|
||||
move = move.substring(1);
|
||||
|
||||
assert move.length() == 3 || move.length() == 2;
|
||||
|
||||
Coordinate ambiguity = new Coordinate(-1, -1);
|
||||
|
||||
// ambiguity
|
||||
if (move.length() == 3) {
|
||||
ambiguity = getAmbiguityPattern(move.charAt(0));
|
||||
move = move.substring(1);
|
||||
}
|
||||
|
||||
Coordinate dest = stringToCoordinate(move);
|
||||
|
||||
Coordinate start = getStartCoord(dest, pieceType, ambiguity, game);
|
||||
|
||||
List<PlayerCommand> cmds = new ArrayList<>();
|
||||
cmds.add(new MoveCommand(new Move(start, dest)));
|
||||
if (promoteCommand != null)
|
||||
cmds.add(promoteCommand);
|
||||
|
||||
return cmds;
|
||||
}
|
||||
|
||||
private static Coordinate getStartCoord(Coordinate dest, Class<? extends Piece> pieceType, Coordinate ambiguity,
|
||||
Game game) {
|
||||
final ChessBoard board = game.getBoard();
|
||||
|
||||
List<Coordinate> starts = board.getAllowedStarts(dest, game.getPlayerTurn());
|
||||
|
||||
assert !starts.isEmpty() : "No moves allowed!";
|
||||
|
||||
for (Coordinate start : starts) {
|
||||
Piece piece = board.pieceAt(start);
|
||||
if (piece.getClass().equals(pieceType) && coordPatternMatch(start, ambiguity))
|
||||
return start;
|
||||
}
|
||||
|
||||
assert false : "There is a small problem ...";
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static int getXCoord(char xPos) {
|
||||
return xPos - 'a';
|
||||
}
|
||||
|
||||
private static int getYCoord(char yPos) {
|
||||
return Coordinate.VALUE_MAX - 1 - (yPos - '1');
|
||||
}
|
||||
|
||||
private static boolean coordPatternMatch(Coordinate coord, Coordinate pattern) {
|
||||
if (pattern.getX() != -1 && coord.getX() != pattern.getX())
|
||||
return false;
|
||||
|
||||
if (pattern.getY() != -1 && coord.getY() != pattern.getY())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static Coordinate getAmbiguityPattern(char amb) {
|
||||
if (Character.isDigit(amb))
|
||||
return new Coordinate(-1, getYCoord(amb));
|
||||
return new Coordinate(getXCoord(amb), -1);
|
||||
}
|
||||
|
||||
private static Coordinate stringToCoordinate(String coordinates) {
|
||||
char xPos = coordinates.charAt(0);
|
||||
char yPos = coordinates.charAt(1);
|
||||
|
||||
return new Coordinate(getXCoord(xPos), getYCoord(yPos));
|
||||
}
|
||||
}
|
||||
28
app/src/main/java/chess/pgn/PgnSimulator.java
Normal file
28
app/src/main/java/chess/pgn/PgnSimulator.java
Normal file
@@ -0,0 +1,28 @@
|
||||
package chess.pgn;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import chess.controller.CommandExecutor;
|
||||
import chess.controller.PlayerCommand;
|
||||
import chess.controller.commands.NewGameCommand;
|
||||
import chess.controller.event.GameAdaptator;
|
||||
import chess.model.Game;
|
||||
|
||||
public class PgnSimulator extends GameAdaptator {
|
||||
|
||||
private final CommandExecutor commandExecutor;
|
||||
private final String pgn;
|
||||
|
||||
public PgnSimulator(CommandExecutor commandExecutor, String pgn) {
|
||||
this.commandExecutor = commandExecutor;
|
||||
this.pgn = pgn;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGameStart() {
|
||||
List<PlayerCommand> cmds = PgnImport.importGame(this.pgn);
|
||||
this.commandExecutor.executeCommands(cmds);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
package chess.simulator;
|
||||
|
||||
import chess.controller.CommandExecutor;
|
||||
import chess.model.Coordinate;
|
||||
import chess.model.Move;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class CastlingTest extends Simulator {
|
||||
public CastlingTest(CommandExecutor commandExecutor) {
|
||||
super(commandExecutor);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Move> getMoves() {
|
||||
return Arrays.asList(
|
||||
// white pawn
|
||||
new Move(new Coordinate(6, 6), new Coordinate(6, 4)),
|
||||
// black knight
|
||||
new Move(new Coordinate(1, 0), new Coordinate(0, 2)),
|
||||
// white bishop
|
||||
new Move(new Coordinate(5, 7), new Coordinate(7, 5)),
|
||||
// black pawn
|
||||
new Move(new Coordinate(1, 1), new Coordinate(1, 2)),
|
||||
// white knight
|
||||
new Move(new Coordinate(6, 7), new Coordinate(5, 5)),
|
||||
// black pawn, bis
|
||||
new Move(new Coordinate(2, 1), new Coordinate(2, 2)));
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
package chess.simulator;
|
||||
|
||||
import chess.controller.CommandExecutor;
|
||||
import chess.model.Coordinate;
|
||||
import chess.model.Move;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class EnPassantTest extends Simulator{
|
||||
|
||||
public EnPassantTest(CommandExecutor commandExecutor) {
|
||||
super(commandExecutor);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected List<Move> getMoves() {
|
||||
return Arrays.asList(
|
||||
// white pawn
|
||||
new Move(new Coordinate(4, 6), new Coordinate(4, 4)),
|
||||
// black pawn 1
|
||||
new Move(new Coordinate(4, 1), new Coordinate(4, 2)),
|
||||
// white pawn
|
||||
new Move(new Coordinate(4, 4), new Coordinate(4, 3)),
|
||||
// black pawn #2
|
||||
new Move(new Coordinate(3, 1), new Coordinate(3, 3)));
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package chess.simulator;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import chess.controller.CommandExecutor;
|
||||
import chess.model.Coordinate;
|
||||
import chess.model.Move;
|
||||
|
||||
public class FoolCheckMate extends Simulator {
|
||||
|
||||
public FoolCheckMate(CommandExecutor commandExecutor) {
|
||||
super(commandExecutor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Move> getMoves() {
|
||||
return Arrays.asList(
|
||||
// white pawn
|
||||
new Move(new Coordinate(5, 6), new Coordinate(5, 5)),
|
||||
// black pawn
|
||||
new Move(new Coordinate(4, 1), new Coordinate(4, 3)),
|
||||
// 2nd white pawn
|
||||
new Move(new Coordinate(6, 6), new Coordinate(6, 4)),
|
||||
// black queen
|
||||
new Move(new Coordinate(3, 0), new Coordinate(7, 4)));
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
package chess.simulator;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import chess.controller.CommandExecutor;
|
||||
import chess.model.Coordinate;
|
||||
import chess.model.Move;
|
||||
|
||||
public class PromoteTest extends Simulator{
|
||||
|
||||
public PromoteTest(CommandExecutor commandExecutor) {
|
||||
super(commandExecutor);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Move> getMoves() {
|
||||
return Arrays.asList(
|
||||
// white pawn
|
||||
new Move(new Coordinate(5, 6), new Coordinate(5, 4)),
|
||||
// black pawn
|
||||
new Move(new Coordinate(4, 1), new Coordinate(4, 3)),
|
||||
// white pawn capture
|
||||
new Move(new Coordinate(5, 4), new Coordinate(4, 3)),
|
||||
// black king
|
||||
new Move(new Coordinate(4, 0), new Coordinate(4, 1)),
|
||||
// white pawn moves
|
||||
new Move(new Coordinate(4, 3), new Coordinate(4, 2)),
|
||||
// black king
|
||||
new Move(new Coordinate(4, 1), new Coordinate(5, 2)),
|
||||
// white pawn moves
|
||||
new Move(new Coordinate(4, 2), new Coordinate(4, 1)),
|
||||
// black king
|
||||
new Move(new Coordinate(5, 2), new Coordinate(6, 2))
|
||||
// white pawn moves
|
||||
// new Move(new Coordinate(4, 1), new Coordinate(4, 0))
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
package chess.simulator;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import chess.controller.CommandExecutor;
|
||||
import chess.controller.commands.MoveCommand;
|
||||
import chess.controller.event.GameAdaptator;
|
||||
import chess.model.Move;
|
||||
import common.Signal0;
|
||||
|
||||
public abstract class Simulator extends GameAdaptator {
|
||||
|
||||
protected final CommandExecutor commandExecutor;
|
||||
|
||||
public final Signal0 onComplete = new Signal0();
|
||||
private int currentMove = 0;
|
||||
|
||||
public Simulator(CommandExecutor commandExecutor) {
|
||||
this.commandExecutor = commandExecutor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGameStart() {
|
||||
for (Move move : getMoves()) {
|
||||
this.commandExecutor.executeCommand(new MoveCommand(move));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBoardUpdate() {
|
||||
currentMove++;
|
||||
if (currentMove == getMoves().size()) {
|
||||
onComplete.emit();
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract List<Move> getMoves();
|
||||
|
||||
}
|
||||
@@ -74,15 +74,15 @@ public class Window extends JFrame implements GameListener {
|
||||
}
|
||||
|
||||
private void buildButtons(JPanel bottom) {
|
||||
castlingButton.addActionListener((_) -> {
|
||||
castlingButton.addActionListener((event) -> {
|
||||
sendCommand(new CastlingCommand(false));
|
||||
});
|
||||
|
||||
bigCastlingButton.addActionListener((_) -> {
|
||||
bigCastlingButton.addActionListener((event) -> {
|
||||
sendCommand(new CastlingCommand(true));
|
||||
});
|
||||
|
||||
undoButton.addActionListener((_) -> {
|
||||
undoButton.addActionListener((event) -> {
|
||||
sendCommand(new UndoCommand());
|
||||
});
|
||||
|
||||
|
||||
1
app/src/main/resources/games/CastlingTest.pgn
Normal file
1
app/src/main/resources/games/CastlingTest.pgn
Normal file
@@ -0,0 +1 @@
|
||||
1.g4 Na6 2.Bh3 b6 3.Nf3 c6
|
||||
1
app/src/main/resources/games/EnPassantTest.pgn
Normal file
1
app/src/main/resources/games/EnPassantTest.pgn
Normal file
@@ -0,0 +1 @@
|
||||
1.e4 e6 2.e5 d5
|
||||
1
app/src/main/resources/games/FoolCheckmate.pgn
Normal file
1
app/src/main/resources/games/FoolCheckmate.pgn
Normal file
@@ -0,0 +1 @@
|
||||
1.f3 e5 2.g4 Qh4# 0-1
|
||||
1
app/src/main/resources/games/PromoteTest.pgn
Normal file
1
app/src/main/resources/games/PromoteTest.pgn
Normal file
@@ -0,0 +1 @@
|
||||
1.f4 e5 2.fxe5 Ke7 3.e6 Kf6 4.e7 Kg6
|
||||
@@ -1,15 +0,0 @@
|
||||
[Event "URS-chT"]
|
||||
[Site "Moscow"]
|
||||
[Date "1963.??.??"]
|
||||
[Round "?"]
|
||||
[White "Listergarten, Leonid B"]
|
||||
[Black "Akopian, Vladimir"]
|
||||
[Result "1-0"]
|
||||
[WhiteElo ""]
|
||||
[BlackElo ""]
|
||||
[ECO "B48"]
|
||||
|
||||
1.e4 c5 2.Nf3 e6 3.d4 cxd4 4.Nxd4 a6 5.Nc3 Qc7 6.Bd3 Nc6 7.Be3 b5 8.a3 Bb7
|
||||
9.O-O Rc8 10.Nxc6 Qxc6 11.Qg4 Nf6 12.Qg3 h5 13.e5 Nd5 14.Ne4 h4 15.Qh3 Qc7
|
||||
16.f4 Nxe3 17.Qxe3 h3 18.gxh3 f5 19.exf6 d5 20.Nf2 Kf7 21.Rae1 Re8 22.Qg3 g5
|
||||
23.fxg5 Qxg3+ 24.hxg3 e5 25.g6+ Kxf6 26.Ng4+ Kg5 27.Rf5+ 1-0
|
||||
@@ -1,12 +1,10 @@
|
||||
1. e4 {1.e4 $1 A fiery start $1} 1... e5 {I like how this game is starting $1} 2. Nc3
|
||||
Bc5 {J'aime un feu chaud.} 3. Nf3 {It's too cold in here for my liking.} 3...
|
||||
Qf6 4. Nd5 Qd6 5. d3 c6 {A fiery position is what I seek $1} 6. Nc3 h6 7. a3 Qg6
|
||||
8. Nxe5 {Things are beginning to heat up, non $2} 8... Qd6 9. Nc4 Qe6 10. d4 Be7
|
||||
11. Ne3 b5 12. Nf5 d5 13. Nxg7+ {That's not very nice.} 13... Kd7 14. Nxe6
|
||||
{Brrrrrr. It is getting cold in here.} 14... fxe6 15. exd5 cxd5 16. Bf4 Nf6 17.
|
||||
Bxb5+ Kd8 18. Qf3 Bd7 19. Be5 {My attack is getting cold, I need to go get some
|
||||
more firewood $1} 19... a6 20. Bxf6 Re8 21. Bxe7+ Kxe7 22. Nxd5+ exd5 23. Qxd5
|
||||
Kf8+ {It's getting toasty in here $1} 24. Be2 Bc6 25. Qd6+ Re7 26. Kf1 Ba4 27. b3
|
||||
1. e4 e5 2. Nc3
|
||||
Bc5 3. Nf3
|
||||
Qf6 4. Nd5 Qd6 5. d3 c6 6. Nc3 h6 7. a3 Qg6
|
||||
8. Nxe5 Qd6 9. Nc4 Qe6 10. d4 Be7
|
||||
11. Ne3 b5 12. Nf5 d5 13. Nxg7+ Kd7 14. Nxe6
|
||||
fxe6 15. exd5 cxd5 16. Bf4 Nf6 17.
|
||||
Bxb5+ Kd8 18. Qf3 Bd7 19. Be5 a6 20. Bxf6 Re8 21. Bxe7+ Kxe7 22. Nxd5+ exd5 23. Qxd5
|
||||
Kf8+ 24. Be2 Bc6 25. Qd6+ Re7 26. Kf1 Ba4 27. b3
|
||||
Nc6 28. bxa4 a5 29. Qxc6 Rd8 30. Qxh6+ Kg8 31. Bc4+ Rf7 32. Qg5+ Kh8 33. Bxf7
|
||||
{C'est très, très mauvais $1} 33... Kh7 34. Qg6+ Kh8 35. Ra2 Rxd4 36. Qg8# {Good
|
||||
play $1 I'll have to throw another log on the fire and try again.} 1-0
|
||||
Kh7 34. Qg6+ Kh8 35. Ra2 Rxd4 36. Qg8# 1-0
|
||||
77
app/src/test/java/chess/PgnTest.java
Normal file
77
app/src/test/java/chess/PgnTest.java
Normal file
@@ -0,0 +1,77 @@
|
||||
package chess;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import chess.ai.DumbAI;
|
||||
import chess.controller.CommandExecutor;
|
||||
import chess.controller.PlayerCommand;
|
||||
import chess.controller.commands.NewGameCommand;
|
||||
import chess.controller.event.GameAdaptator;
|
||||
import chess.model.Color;
|
||||
import chess.model.Game;
|
||||
import chess.pgn.PgnExport;
|
||||
import chess.pgn.PgnImport;
|
||||
|
||||
public class PgnTest {
|
||||
|
||||
private Game getRandomGame() {
|
||||
Game game = new Game();
|
||||
CommandExecutor commandExecutor = new CommandExecutor(game);
|
||||
|
||||
commandExecutor.addListener(new DumbAI(commandExecutor, Color.White));
|
||||
commandExecutor.addListener(new DumbAI(commandExecutor, Color.Black));
|
||||
|
||||
commandExecutor.addListener(new GameAdaptator() {
|
||||
@Override
|
||||
public void onGameEnd() {
|
||||
synchronized (game) {
|
||||
game.notifyAll();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
commandExecutor.executeCommand(new NewGameCommand());
|
||||
|
||||
synchronized (game) {
|
||||
try {
|
||||
game.wait();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
commandExecutor.close();
|
||||
|
||||
return game;
|
||||
}
|
||||
|
||||
private void importExport() {
|
||||
Game game = getRandomGame();
|
||||
|
||||
String pgnContent = PgnExport.exportGame(game);
|
||||
|
||||
List<PlayerCommand> moves = PgnImport.importGame(pgnContent);
|
||||
|
||||
Game game2 = new Game();
|
||||
CommandExecutor commandExecutor = new CommandExecutor(game2);
|
||||
commandExecutor.executeCommand(new NewGameCommand());
|
||||
|
||||
commandExecutor.executeCommands(moves);
|
||||
|
||||
String pgnContent2 = PgnExport.exportGame(game2);
|
||||
|
||||
commandExecutor.close();
|
||||
|
||||
assertEquals(pgnContent, pgnContent2);
|
||||
}
|
||||
|
||||
@Test void importExports() {
|
||||
for (int i = 0; i < 50; i++) {
|
||||
importExport();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user