Help with PGN to FEN strings with move list
Opened this issue · 1 comments
atenonai commented
I would like to achieve the following:
- Use a PGN-file as input.
- Output individual FEN strings for each position from a chosen perspective, including variations. The FEN position should be before the opposite color made their move.
- Include a move list after the FEN string (the first move would be the opposite color, and the second move would be the move from the chosen perspective).
- If any moves had annotations (comments/
[%csl ...]
/[%cal ...]
) those should be preserved in the move list as well.
Example:
With the following PGN as input, and black as the chosen perspective…
[Event "?"]
[Site "?"]
[Date "????.??.??"]
[Round "?"]
[White "?"]
[Black "?"]
[Result "*"]
1. e4 c5 { Sicilian } { [%csl Gd4][%cal Gc5d4] } 2. Nf3 (2. Nc3 { Closed Sicilian } 2... d6) 2... d6 *
…the desired output would be:
[FEN "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"]
1. e4 c5 { Sicilian } { [%csl Gd4][%cal Gc5d4] }
[FEN "rnbqkbnr/pp1ppppp/8/2p5/4P3/8/PPPP1PPP/RNBQKBNR w KQkq - 0 2"]
2. Nf3 d6
[FEN "rnbqkbnr/pp1ppppp/8/2p5/4P3/8/PPPP1PPP/RNBQKBNR w KQkq - 0 2"]
2. Nc3 { Closed Sicilian } 2... d6
I hope that all made sense.
Is this possible? I would be grateful for any pointers on how to achieve it.
atenonai commented
I figured out the first parts!
How can I include not only moves but also the move numbers and comments/annotations from the PGN? If anyone could provide some pointers that would be great.
import chess
import chess.pgn
pgn_file = '/path'
repertoire_color = 'black'
if repertoire_color == 'black':
setup_positions = chess.WHITE # FEN positions will be before opponents move
elif repertoire_color == 'white':
setup_positions = chess.BLACK # FEN positions will be before opponents move
with open(pgn_file) as pgn:
parsed_pgn = chess.pgn.read_game(pgn)
def extract_positions(node, color):
if node.board().turn == color:
fen = node.board().fen()
if node.variations:
# Get opponent move
for variation in node.variations:
opponent_move = variation.move
# Convert move to algebraic notation
algebraic_opponent_move = node.board().san(opponent_move)
if variation.variations:
# For each found move, check if there's a response in the repertoire
response_move = variation.variations[0].move
if response_move:
# Convert move to algebraic notation
algebraic_response_move = variation.board().san(response_move)
# Print the position and move pair
print(f'[FEN "{fen}"]\n{algebraic_opponent_move} {algebraic_response_move}\n')
# Recursively process nodes to extract all positions (both main line and sidelines)
for variation in node.variations:
extract_positions(variation, color)
extract_positions(parsed_pgn, setup_positions)