Created: 2017-05-17 Wed 20:30
1. e4 e5 2. Nf3 Nc6 3. Bc4 Nf6 4. Ng5 d5 5. exd5 Nx5d 6. Nxf7 Kxf7
Portable Game Notation plain text, computer-processible format for recording chess games.
We're going to write a parser for it…
pip install pyparsing
from pyparsing import * # noqa :-)
1. e4 e5
move_number = Word(nums) + Literal(".")
file_coord = oneOf("a b c d e f g h")
rank_coord = oneOf("1 2 3 4 5 6 7 8")
Pawn half-move is just a file and a rank.
pawn_move = file_coord + rank_coord
Any idea how?
piece = oneOf("K Q N B R")
A piece half-move has the piece prefix and coordinates.
piece_move = piece + file_coord + rank_coord
Capture involves having literal `x` in between coordinates.
capture = Literal("x")
Start from a file (letter), capture and end with coordinates.
pawn_capture = file_coord + capture + file_coord + rank_coord
Same as pawn, but have a piece prefix instead of file.
piece_capture = piece + capture + file_coord + rank_coord
A half move is either a:
half_move = Combine(pawn_move | pawn_capture | piece_move | piece_capture)
A move is a:
move = Group(Suppress(move_number) + half_move + half_move)
We started with a PGN, so we finish with:
pgnGrammar = ZeroOrMore(move)
pgn = pgnGrammar.parseString("""
1. e4 e5
2. Nf3 Nc6
3. Bc4 Nf6
4. Ng5 d5
5. exd5 Nxd5
6. Nxf7 Kxf7""")
[list(m) for m in pgn]
[['e4', 'e5'], ['Nf3', 'Nc6'], ['Bc4', 'Nf6'], ['Ng5', 'd5'], ['exd5', 'Nxd5'], ['Nxf7', 'Kxf7']]