PGN Parser for Chess Games
Overview
This is a simple PGN (Portable Game Notation) parser for chess games written in Rust. It allows you to parse PGN files and extract information about chess games.
Crate
https://crates.io/crates/pgn_parser
Usage
Command-Line Interface (CLI)
The PGN parser comes with a CLI offering the following subcommands:
Help
Display help information for the PGN parser CLI:
pgn_parser help
Parse
Parse a PGN file and output game information. This subcommand requires two arguments:
-i or --input: Specify the input file. -o or --output: Specify the output file for parsed information.
pgn_parser parse -i input.txt -o output.txt
If you don't specify an output file using the -o or --output option, the game information will be written directly to your command-line interface (CLI).
Grammar
Represents a metadata block enclosed in square brackets, consisting of two adjacent words enclosed in double quotes.
metadata_block = { "[" ~ word ~ "\"" ~ word ~ "\"]" }
Represents a sequence of characters that is not "]" or """ (double quote), allowing any character except those. It captures one or more characters.
word = { (!("]" | "\"") ~ ANY)+ }
Represents a character from 'a' to 'h', inclusive, representing chess files.
files = { 'a'..'h' }
Represents a character from '1' to '8', inclusive, representing chess ranks.
ranks = { '1' .. '8' }
Represents a comment for a move enclosed in curly braces. It captures any characters except '}' (closing curly brace).
move_comment = { "{" ~ (!("}") ~ ANY)* ~ "}" }
Represents a chess piece abbreviation: "K" (king), "Q" (queen), "R" (rook), "B" (bishop), or "N" (knight). It is optional.
piece = { ("K" | "Q" | "R" | "B" | "N")? }
Represents a castling move: "O-O-O" (queenside castling) or "O-O" (kingside castling).
castle = { ("O-O-O" | "O-O") }
Represents a move in chess
move_piece_with_capture = { piece ~ (files)? ~ "x" ~ files ~ ranks }
move_piece_without_capture = { piece ~ (files){1,2} ~ ranks }
move_piece = { (move_piece_with_capture | move_piece_without_capture)}
complete_move = { (move_piece | castle) ~ ("+" | "#")? }
Represents a pair of moves in chess notation, including the move number and optional move comments.
move_pair = { (ASCII_DIGIT)+ ~ "." ~ complete_move ~ move_comment? ~ complete_move? ~ move_comment? }
Represents a list of move pairs.
move_list = { (move_pair)+ }
Represents the result of a chess game, either "1/2-1/2" (draw), "1-0" (white wins), or "0-1" (black wins).
game_result = { "1/2-1/2" | "1-0" | "0-1"
Represents a complete chess game, starting with the start of input (SOI), followed by optional metadata blocks, a move list, a game result, and the end of input (EOI).
game = { SOI ~ (metadata_block)* ~ move_list ~ game_result ~ EOI}
Example
Input example
[Event "Rated Blitz game"]
[Site "https://lichess.org/GI7wh3rQ"]
[Date "2023.11.13"]
[White "Ilya_Sh"]
[Black "Jlquilo"]
[Result "1-0"]
[UTCDate "2023.11.13"]
[UTCTime "14:26:46"]
[WhiteElo "1886"]
[BlackElo "1886"]
[WhiteRatingDiff "+6"]
[BlackRatingDiff "-6"]
[Variant "Standard"]
[TimeControl "180+0"]
[ECO "B01"]
[Opening "Scandinavian Defense: Valencian Variation"]
[Termination "Normal"]
[Annotator "lichess.org"]
1. e4 d5 2. exd5 Qxd5 3. Nc3 Qd8 { B01 Scandinavian Defense: Valencian Variation } 4. d4 e6 5. Nf3 c6 6. Bd3 Be7 7. O-O b5 8. a3 a5 9. Ne4 Ba6 10. Nc5 Bc8 11. Re1 Nf6 12. Bg5 O-O 13. c3 Na6 14. Nxa6 Bxa6 15. Qc2 h6 16. Bxf6 Bxf6 17. Ne5 Qc7 18. Re3 Rfc8 19. Rh3 Bxe5 20. dxe5 Qxe5 21. g4 c5 22. Be4 Rab8 23. Rg3 Qg5 24. Kg2 b4 25. h4 Qxh4 26. g5 h5 27. Rh1 Qf4 28. Rxh5 Bb7 29. Bxb7 Rxb7 30. Qh7+ Kf8 31. Qh8+ Ke7 32. Qxc8 Qe4+ 33. Kh2 Rd7 34. Qxc5+ { Black resigns. } 1-0
Output
Game Metadata
Event: Rated Blitz game
Site: https://lichess.org/GI7wh3rQ
Date: 2023.11.13
White: Ilya_Sh
Black: Jlquilo
Result: 1-0
UTCDate: 2023.11.13
UTCTime: 14:26:46
WhiteElo: 1886
BlackElo: 1886
WhiteRatingDiff: +6
BlackRatingDiff: -6
Variant: Standard
TimeControl: 180+0
ECO: B01
Opening: Scandinavian Defense: Valencian Variation
Termination: Normal
Annotator: lichess.org
List of moves
Move #1
White: e4 Black: d5
Move #2
White: exd5 Black: Qxd5
Move #3
White: Nc3 Black: Qd8 { B01 Scandinavian Defense: Valencian Variation }
Move #4
White: d4 Black: e6
Move #5
White: Nf3 Black: c6
Move #6
White: Bd3 Black: Be7
Move #7
White: O-O Black: b5
Move #8
White: a3 Black: a5
Move #9
White: Ne4 Black: Ba6
Move #10
White: Nc5 Black: Bc8
Move #11
White: Re1 Black: Nf6
Move #12
White: Bg5 Black: O-O
Move #13
White: c3 Black: Na6
Move #14
White: Nxa6 Black: Bxa6
Move #15
White: Qc2 Black: h6
Move #16
White: Bxf6 Black: Bxf6
Move #17
White: Ne5 Black: Qc7
Move #18
White: Re3 Black: Rfc8
Move #19
White: Rh3 Black: Bxe5
Move #20
White: dxe5 Black: Qxe5
Move #21
White: g4 Black: c5
Move #22
White: Be4 Black: Rab8
Move #23
White: Rg3 Black: Qg5
Move #24
White: Kg2 Black: b4
Move #25
White: h4 Black: Qxh4
Move #26
White: g5 Black: h5
Move #27
White: Rh1 Black: Qf4
Move #28
White: Rxh5 Black: Bb7
Move #29
White: Bxb7 Black: Rxb7
Move #30
White: Qh7+ Black: Kf8
Move #31
White: Qh8+ Black: Ke7
Move #32
White: Qxc8 Black: Qe4+
Move #33
White: Kh2 Black: Rd7
Move #34
White: Qxc5+ { Black resigns. } Black:
Game Result
1-0