Crate pgn_reader [] [src]

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:

Flow

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_bytes(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

InvalidNag

Error when parsing an invalid NAG.

Iter

View a Reader as an iterator.

Nag

A numeric annotation glyph like ?, !! or $42.

Reader

Reads a PGN.

Skip

Tell the reader to skip over a game or variation.

Enums

CastlingSide

KingSide (O-O) or QueenSide (O-O-O).

Color

White or Black.

Outcome

Outcome of a game.

Role

Piece types: Pawn, Knight, Bishop, Rook, Queen, King.

San

A move in Standard Algebraic Notation.

Square

A square index.

Traits

Visitor

Consumes games from a reader.