Crate pgn_reader
source ·Expand description
A fast non-allocating reader for chess games in PGN notation.
Reader
parses games and calls methods of a user provided Visitor
.
Implementing custom visitors allows for maximum flexibility:
- The reader itself does not allocate. The visitor can decide if and how to represent games in memory.
- The reader does not validate move legality. This allows implementing support for custom chess variants, or delaying move validation.
- The visitor can signal to the reader that it does not care about a game or variation.
Flow
Visitor methods are called in this order:
Examples
A visitor that counts the number of syntactically valid moves in mainline of each game.
extern crate pgn_reader;
use pgn_reader::{Visitor, Skip, Reader, San};
struct MoveCounter {
moves: usize,
}
impl MoveCounter {
fn new() -> MoveCounter {
MoveCounter { moves: 0 }
}
}
impl<'pgn> Visitor<'pgn> for MoveCounter {
type Result = usize;
fn begin_game(&mut self) {
self.moves = 0;
}
fn san(&mut self, _san: San) {
self.moves += 1;
}
fn begin_variation(&mut self) -> Skip {
Skip(true) // stay in the mainline
}
fn end_game(&mut self, _game: &'pgn [u8]) -> Self::Result {
self.moves
}
}
fn main() {
let pgn = b"1. e4 e5 2. Nf3 (2. f4)
{ game paused due to bad weather }
2... Nf6 *";
let mut counter = MoveCounter::new();
let reader = Reader::new(&mut counter, pgn);
let moves: usize = reader.into_iter().sum();
assert_eq!(moves, 4);
}
A visitor that returns the final position using Shakmaty.
extern crate pgn_reader;
extern crate shakmaty;
use pgn_reader::{Visitor, Skip, Reader, San};
use shakmaty::{Chess, Position};
use shakmaty::fen::Fen;
struct LastPosition {
pos: Chess,
}
impl LastPosition {
fn new() -> LastPosition {
LastPosition { pos: Chess::default() }
}
}
impl<'pgn> Visitor<'pgn> for LastPosition {
type Result = Chess;
fn header(&mut self, key: &'pgn [u8], value: &'pgn [u8]) {
// Support games from a non-standard starting position.
if key == b"FEN" {
let pos = Fen::from_ascii(value).ok()
.and_then(|f| f.position().ok());
if let Some(pos) = pos {
self.pos = pos;
}
}
}
fn begin_variation(&mut self) -> Skip {
Skip(true) // stay in the mainline
}
fn san(&mut self, san: San) {
if let Ok(m) = san.to_move(&self.pos) {
self.pos.play_unchecked(&m);
}
}
fn end_game(&mut self, _game: &'pgn [u8]) -> Self::Result {
::std::mem::replace(&mut self.pos, Chess::default())
}
}
fn main() {
let pgn = b"1. f3 e5 2. g4 Qh4#";
let mut visitor = LastPosition::new();
let mut reader = Reader::new(&mut visitor, pgn);
let pos = reader.read_game();
assert!(pos.map_or(false, |p| p.is_checkmate()));
}
Structs
Error when parsing an invalid NAG.
A numeric annotation glyph like
?
, !!
or $42
.Reads a PGN.
Tell the reader to skip over a game or variation.
Enums
KingSide
(O-O) or QueenSide
(O-O-O).White
or Black
.Outcome of a game.
Piece types:
Pawn
, Knight
, Bishop
, Rook
, Queen
, King
.A move in Standard Algebraic Notation.
A square index.
Traits
Consumes games from a reader.