feat(io): implement PgnExporter.exportGameContext with move replay

PgnExporter now extends GameContextExport and implements exportGameContext,
which replays moves from GameContext.initial to reconstruct HistoryMove records
with proper castling/promotion info before generating PGN.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-05 13:20:59 +02:00
parent f0316013fc
commit 09a70ed435
@@ -1,10 +1,41 @@
package de.nowchess.io.pgn
import de.nowchess.api.board.*
import de.nowchess.api.move.PromotionPiece
import de.nowchess.api.game.{GameHistory, HistoryMove}
import de.nowchess.api.move.{PromotionPiece, MoveType}
import de.nowchess.api.game.{GameHistory, HistoryMove, GameContext}
import de.nowchess.io.GameContextExport
import de.nowchess.rules.sets.DefaultRules
object PgnExporter:
object PgnExporter extends GameContextExport:
/** Export a GameContext to PGN format by replaying all moves and reconstructing HistoryMove records. */
def exportGameContext(context: GameContext): String =
val headers = Map(
"Event" -> "?",
"White" -> "?",
"Black" -> "?",
"Result" -> "*"
)
// Replay all moves to reconstruct HistoryMove records with full info
val historyMoves = scala.collection.mutable.ListBuffer[HistoryMove]()
var ctx = GameContext.initial
for move <- context.moves do
val color = ctx.turn
val pieceType = ctx.board.pieceAt(move.from).map(_.pieceType).getOrElse(PieceType.Pawn)
val isCapture = ctx.board.pieceAt(move.to).isDefined || move.moveType == MoveType.EnPassant
val castleSide = move.moveType match
case MoveType.CastleKingside => Some("Kingside")
case MoveType.CastleQueenside => Some("Queenside")
case _ => None
val promotionPiece = move.moveType match
case MoveType.Promotion(pp) => Some(pp)
case _ => None
historyMoves += HistoryMove(move.from, move.to, castleSide, promotionPiece, pieceType, isCapture)
ctx = DefaultRules.applyMove(ctx, move)
val history = GameHistory(historyMoves.toList, context.halfMoveClock)
exportGame(headers, history)
/** Export a game with headers and history to PGN format. */
def exportGame(headers: Map[String, String], history: GameHistory): String =