173 lines
4.8 KiB
Java
173 lines
4.8 KiB
Java
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));
|
|
}
|
|
}
|