238 lines
6.1 KiB
Java
238 lines
6.1 KiB
Java
package chess.pgn;
|
|
|
|
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;
|
|
import chess.controller.commands.MoveCommand;
|
|
import chess.controller.commands.NewGameCommand;
|
|
import chess.controller.commands.PromoteCommand;
|
|
import chess.controller.event.EmptyGameDispatcher;
|
|
import chess.model.Color;
|
|
import chess.model.Coordinate;
|
|
import chess.model.Game;
|
|
import chess.model.Move;
|
|
import chess.model.Piece;
|
|
import chess.model.pieces.Pawn;
|
|
|
|
/**
|
|
* Export a game to PGN format.
|
|
*/
|
|
|
|
public class PgnExport {
|
|
|
|
private static final PiecePgnName piecePgnName = new PiecePgnName();
|
|
|
|
private static Piece pieceAt(CommandExecutor commandExecutor, Coordinate coordinate) {
|
|
GetPieceAtCommand cmd = new GetPieceAtCommand(coordinate);
|
|
commandExecutor.executeCommand(cmd);
|
|
return cmd.getPiece();
|
|
}
|
|
|
|
private static List<Move> playerMoves(CommandExecutor commandExecutor) {
|
|
GetPlayerMovesCommand cmd = new GetPlayerMovesCommand();
|
|
commandExecutor.executeCommand(cmd);
|
|
return cmd.getMoves();
|
|
}
|
|
|
|
private static String gameEnd(Game game) {
|
|
switch (game.checkGameStatus(game.getPlayerTurn())) {
|
|
case Draw:
|
|
case Pat:
|
|
return "1/2-1/2";
|
|
|
|
case CheckMate:
|
|
if (game.getPlayerTurn() == Color.White)
|
|
return "0-1";
|
|
return "1-0";
|
|
|
|
default:
|
|
return "";
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Resolve PGN ambiguity in the case of two pieces of the same type able to move on the same square.
|
|
* @param cmdExec the command executor attached to the game
|
|
* @param pieceMove move of the piece
|
|
* @return the character that solves the eventual ambiguity, empty if no ambiguity to start with
|
|
*/
|
|
private static String resolveAmbiguity(CommandExecutor cmdExec, Move pieceMove) {
|
|
Piece movingPiece = pieceAt(cmdExec, pieceMove.getStart());
|
|
|
|
assert movingPiece != null;
|
|
|
|
if (movingPiece instanceof Pawn)
|
|
return "";
|
|
|
|
List<Move> moves = playerMoves(cmdExec);
|
|
|
|
for (Move move : moves) {
|
|
if (move.equals(pieceMove) || !move.getFinish().equals(pieceMove.getFinish()))
|
|
continue;
|
|
|
|
Piece otherPiece = pieceAt(cmdExec, move.getStart());
|
|
|
|
// checking type of piece
|
|
if (!otherPiece.getClass().equals(movingPiece.getClass()))
|
|
continue;
|
|
|
|
String startPos = toString(pieceMove.getStart());
|
|
|
|
if (move.getStart().getX() != pieceMove.getStart().getX())
|
|
// not on the same column
|
|
return Character.toString(startPos.charAt(0));
|
|
else
|
|
return Character.toString(startPos.charAt(1));
|
|
|
|
}
|
|
|
|
return "";
|
|
}
|
|
|
|
/**
|
|
* From a move, get the capture-part of the associated PGN string.
|
|
* @param move the move
|
|
* @param movingPiece the piece that is moving
|
|
* @return the capture string of the PGN move
|
|
*/
|
|
private static String capture(MoveCommand move, Piece movingPiece) {
|
|
String result = "";
|
|
if (move.getDeadPiece() != null) {
|
|
if (movingPiece instanceof Pawn) {
|
|
result += toString(move.getMove().getStart()).charAt(0);
|
|
}
|
|
result += "x";
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private static String promote(PlayerCommand nextCommand) {
|
|
if (nextCommand != null && nextCommand instanceof PromoteCommand promoteCommand) {
|
|
String result = "=";
|
|
result += switch (promoteCommand.getPromoteType()) {
|
|
case Bishop -> "B";
|
|
case Knight -> "N";
|
|
case Queen -> "Q";
|
|
case Rook -> "R";
|
|
};
|
|
return result;
|
|
}
|
|
return "";
|
|
}
|
|
|
|
private static String castling(CastlingCommand castlingCommand) {
|
|
String result = "O-O";
|
|
if (castlingCommand.isBigCastling())
|
|
result += "-O";
|
|
return result;
|
|
}
|
|
|
|
private static String checkCheckMate(Game game) {
|
|
switch (game.checkGameStatus(game.getPlayerTurn())) {
|
|
case CheckMate:
|
|
return "#";
|
|
|
|
case Check:
|
|
return "+";
|
|
|
|
default:
|
|
return "";
|
|
}
|
|
}
|
|
|
|
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) {
|
|
|
|
Piece movingPiece = virtualGame.getBoard().pieceAt(move.getMove().getStart());
|
|
|
|
assert movingPiece != null;
|
|
|
|
// piece name
|
|
result += piecePgnName.visit(movingPiece);
|
|
|
|
// ambiguious start
|
|
result += resolveAmbiguity(executor, move.getMove());
|
|
|
|
// capture
|
|
result += capture(move, movingPiece);
|
|
|
|
// end cell
|
|
result += toString(move.getMove().getFinish());
|
|
|
|
// promote
|
|
result += promote(nextCommand);
|
|
|
|
} else if (cmd instanceof CastlingCommand castlingCommand) {
|
|
result += castling(castlingCommand);
|
|
}
|
|
|
|
CommandResult commandResult = executor.executeCommand(cmd);
|
|
|
|
// check or checkmate
|
|
result += checkCheckMate(virtualGame);
|
|
|
|
result += " ";
|
|
|
|
return new MoveResult(result, commandResult);
|
|
}
|
|
|
|
public static String exportGame(Game game) {
|
|
|
|
Game virtualGame = new Game();
|
|
|
|
CommandExecutor executor = new CommandExecutor(virtualGame, new EmptyGameDispatcher());
|
|
executor.executeCommand(new NewGameCommand());
|
|
|
|
List<PlayerCommand> commands = game.getMoves();
|
|
String result = "";
|
|
|
|
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);
|
|
}
|
|
MoveResult moveResult = printMove(cmd, nextCommand, virtualGame, executor);
|
|
if (moveResult.commandResult() == CommandResult.Moved && virtualGame.getPlayerTurn() == Color.Black) {
|
|
result += tour + ".";
|
|
tour++;
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
public static String toString(Coordinate coordinate) {
|
|
String letters = "abcdefgh";
|
|
String numbers = "87654321";
|
|
return Character.toString(letters.charAt(coordinate.getX())) + numbers.charAt(coordinate.getY());
|
|
}
|
|
}
|