Add PGN export and a Copy PGN button for finished games

- Record moves in standard algebraic notation (GameState.SanHistory), built at
  move time in ChessService (captures, disambiguation, castling, promotion,
  en passant, and the check/mate suffix)
- Add PgnExporter.ToPgn (seven-tag header + movetext + result) and a
  GET /api/chess/{gameId}/pgn endpoint
- Show a Copy PGN button when a game ends on both the play and watch pages,
  prefetching the PGN so it works during the post-game cleanup window

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
This commit is contained in:
Josh-Heaps
2026-06-08 19:14:39 -06:00
co-authored by Claude Opus 4.8
parent d87cea572f
commit b651683e63
11 changed files with 255 additions and 0 deletions
@@ -1,5 +1,6 @@
using JoshHeaps.Net.Hubs;
using JoshHeaps.Net.Models;
using JoshHeaps.Net.Services.Implementations;
using JoshHeaps.Net.Services.Interfaces;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SignalR;
@@ -280,6 +281,18 @@ public class ChessController(
return Ok();
}
/// <summary>
/// Export a game as PGN (works while the game is still in memory after it ends).
/// </summary>
[HttpGet("{gameId}/pgn")]
public ActionResult GetPgn(Guid gameId)
{
if (!_games.TryGetValue(gameId, out var gameState))
return NotFound("Game not found");
return Content(gameState.ToPgn(), "application/x-chess-pgn");
}
/// <summary>
/// Get the legal moves for a specific piece in a specific game.
/// </summary>