pgn_filter

For searching/filtering pgn files of chess games.

Features

Position Definitions

Games are stored in a collection of type pgn_filter::Games, and can be filtered using the search method. The search method takes a BoardFilter definition, which specifies the permitted number of pieces of each type, and returns a new collection containing just those games which match the definition.

For example, the following filter matches 5-4 rook-and-pawn endings, i.e. those with 5 white pawns, 4 black pawns and a rook on either side:

let filter = pgn_filter::Board::must_have() .exactly(1, "R") .exactly(1, "r") .exactly(5, "P") .exactly(4, "p");

Notice that the filter is constructed from a base filter obtained by calling "must_have". This base filter recognises positions with exactly one king of each colour, and no pieces or pawns. You build up the filter by adding a relation for each of the pieces you require. If you add a second filter for a given piece, the second filter will replace the first one.

The available filters are:

Example: Extracting all 5-4 R+P endings

The following example shows how to construct a filter to identify 5-4 rook endings, and save the selected games to a file.

``` // Create a database and add some games let mut db = pgnfilter::Games::new(); db.addgames("examples/twic1356.pgn").unwrap();

// Display some information println!("Database has {} game(s)", db.iter().count());

// Create a position definition for 5-4 rook endings let filter = pgnfilter::Board::musthave() .exactly(1, "R") .exactly(1, "r") .exactly(5, "P") .exactly(4, "p");

// Extract those games which at some point reach let selected = db.search(&filter); selected.to_file("rook-endings.pgn").unwrap();

// Report and save result println!("Selected {} out of {} games", selected.iter().count(), db.iter().count()); ```

Example: Study a game move-by-move

The Game#play_game method takes a closure/function, which is passed the current board and next move after each half move. The following example prints out the board position and information to create a trace of the game:

``` let fischer = pgnfilter::Games::fromfile("examples/fischer.pgn").unwrap();

println!("File has {} game(s)", fischer.games.len());

if fischer.games.len() > 0 { let game = &fischer.games[0];

game.play_game(|board, next_move| {
    println!("{}", board.to_string());
    match next_move {
        Some(mv) => {
            // next move in the game
            println!(
                "Move {}: {}{}",
                board.fullmove_number,
                if board.white_to_move { "" } else { "..." },
                mv
            );
            println!("");
        }
        None => {
            // game over, so display the result
            println!("Result: {}", game.header.get("Result").unwrap());
        }
    };
});

} ```

Sample output:

``` File has 1 game(s) rnbqkbnr pppppppp ........ ........ ........ ........ PPPPPPPP RNBQKBNR

Move 1: e4

rnbqkbnr pppppppp ........ ........ ....P... ........ PPPP.PPP RNBQKBNR

Move 1: ...e5

rnbqkbnr pppp.ppp ........ ....p... ....P... ........ PPPP.PPP RNBQKBNR

Move 2: Nf3

rnbqkbnr pppp.ppp ........ ....p... ....P... .....N.. PPPP.PPP RNBQKB.R

Move 2: ...Nc6

r.bqkbnr pppp.ppp ..n..... ....p... ....P... .....N.. PPPP.PPP RNBQKB.R

Move 3: Bb5 ```