Skip to content

moritzmyrz/ply

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

11 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ply

Fast Rust toolkit for PGN parsing, legal move generation, and chess game analysis.

Overview

ply is an open-source Rust chess infrastructure project focused on correctness, predictable behavior, and practical tooling.

It provides a composable core for:

  • parsing and serializing FEN,
  • representing board state and applying legal moves,
  • parsing PGN and reconstructing games from SAN,
  • extracting per-game summaries and aggregate statistics,
  • exporting analysis data as JSON,
  • running these workflows from a CLI.

This project is not a top-tier competitive chess engine and does not currently implement evaluation/search designed to compete with Stockfish-class engines. The primary goal is reliable chess data infrastructure for developers, analysts, and downstream tooling.

Why this project?

  • Build a clean Rust codebase for chess data processing that is easy to inspect and extend.
  • Keep move legality and replay logic in a reusable library, with a thin CLI layer on top.
  • Support real workflows: validating PGN collections, summarizing games, and inspecting positions.

Features

  • FEN parsing and serialization
    • strict 6-field validation (board, side-to-move, castling, en-passant, halfmove, fullmove)
    • normalized round-trip rendering
  • Board and position representation
    • typed model for color, piece kind, square, castling rights, clocks, and side-to-move
  • Legal move generation
    • pseudo-legal generation + king safety filtering
    • castling, en-passant, and promotion handling
  • PGN parsing and game reconstruction
    • tag parsing and movetext tokenization
    • SAN move resolution against generated legal moves
    • full game replay to final position
  • Per-game summaries and aggregate statistics
    • player/result/plies summary fields
    • opening move frequencies (White and Black first moves)
    • castling distribution (kingside, queenside, no castling)
    • total/average captures, checks, and promotions
    • average game length by result type
  • Perft support
    • reusable perft API for legal move generation validation
    • CLI command for quick node-count checks
  • JSON export
    • structured JSON for aggregate stats and per-game summaries
  • CLI workflows
    • validate PGN files
    • summarize reconstructed games
    • print aggregate stats (text or JSON)
    • inspect FEN positions and legal moves
    • run perft against startpos or custom FEN

Correctness and validation

ply treats correctness as a core requirement and validates behavior at multiple layers:

  • Move legality validation: legal move generation is covered by integration tests for baseline positions and special rules like en passant.
  • Replay validation: PGN reconstruction resolves SAN against generated legal moves and is exercised with fixture-based tests.
  • Perft regression checks: known perft node counts (including start position and tricky reference positions) are tested to catch move-generation regressions.
  • CLI-level checks: command integration tests verify that key workflows (validate, stats --json, perft) execute and emit expected output.

Current implementation boundaries

  • PGN comments and variations are stripped during tokenization (baseline parser behavior).
  • SAN handling supports common game notation used in standard game files; edge-case PGN dialects may require further expansion.
  • No engine evaluation/search module yet.

Example CLI usage

# Validate whether games can be reconstructed legally
ply validate games.pgn

# Same, but print a line per failed game (replay error)
ply validate games.pgn --verbose

# Print one-line summaries per game
ply summarize games.pgn

# Compute aggregate stats and emit JSON
ply stats games.pgn --json

# Parse a FEN and list legal moves in coordinate notation
ply fen "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1" --legal-moves

# Run perft on start position (or pass --fen "<fen>")
ply perft --depth 3

You can also run the binary through Cargo during development:

cargo run -- summarize tests/fixtures/sample_games.pgn

Example output

Human-readable summary (ply summarize tests/fixtures/sample_games.pgn):

1. WhitePlayer vs BlackPlayer | result=1-0 | plies=7
2. Alpha vs Beta | result=1/2-1/2 | plies=8

JSON stats (ply stats tests/fixtures/sample_games.pgn --json):

{
  "stats": {
    "average_captures": 0.5,
    "average_checks": 0.5,
    "average_plies": 7.5,
    "average_plies_black_wins": null,
    "average_plies_draws": 8.0,
    "average_plies_unresolved": null,
    "average_plies_white_wins": 7.0,
    "average_promotions": 0.0,
    "black_first_moves": {
      "d5": 1,
      "e5": 1
    },
    "black_wins": 0,
    "draws": 1,
    "games": 2,
    "games_with_kingside_castle": 0,
    "games_with_no_castling": 2,
    "games_with_queenside_castle": 0,
    "total_captures": 1,
    "total_checks": 1,
    "total_plies": 15,
    "total_promotions": 0,
    "unresolved": 0,
    "white_first_moves": {
      "d4": 1,
      "e4": 1
    },
    "white_wins": 1
  },
  "games": [
    {
      "event": "Miniature",
      "white": "WhitePlayer",
      "black": "BlackPlayer",
      "result": "1-0",
      "plies": 7,
      "winner": "white"
    },
    {
      "event": "DrawnGame",
      "white": "Alpha",
      "black": "Beta",
      "result": "1/2-1/2",
      "plies": 8,
      "winner": null
    }
  ]
}

Perft (ply perft --depth 3):

depth: 3
nodes: 8902
elapsed_ms: 24
nps: 357520

Architecture

The repository is organized as a library-first core with a small command-line frontend.

  • src/lib.rs
    • public module surface for library users
  • src/board/mod.rs
    • core chess domain model (pieces, squares, position, castling rights, move struct)
  • src/fen.rs
    • FEN parser/serializer and validation errors
  • src/movegen.rs
    • pseudo-legal and legal move generation, attack detection, and state transitions
  • src/pgn/
    • PGN parsing (parse.rs), SAN resolution (san.rs), and replay (replay.rs)
  • src/stats.rs
    • summary and aggregate metrics over reconstructed games
  • src/export.rs
    • JSON DTO conversion layer for stable CLI output
  • src/main.rs
    • clap-based CLI command routing
  • tests/
    • integration coverage for FEN/movegen, PGN replay/stats, and CLI behavior
  • benches/movegen.rs
    • criterion benchmark for legal move generation throughput from start position

Installation

Clone and build

git clone https://github.com/moritzmyrz/ply.git
cd ply
cargo build

Run the CLI locally

cargo run -- validate tests/fixtures/sample_games.pgn
cargo run -- summarize tests/fixtures/sample_games.pgn
cargo run -- stats tests/fixtures/sample_games.pgn --json
cargo run -- fen "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1" --legal-moves
cargo run -- perft --depth 3

Run tests

cargo test

Development

The project includes a simple Makefile for common development commands:

make fmt    # cargo fmt
make lint   # cargo clippy --all-targets --all-features -- -D warnings
make test   # cargo test
make bench  # cargo bench

If you prefer direct Cargo commands:

cargo fmt
cargo clippy --all-targets --all-features -- -D warnings
cargo test
cargo bench

Roadmap

  • Improve opening metadata extraction and ECO classification support.
  • Introduce Zobrist hashing for efficient position keys and caching.
  • Add evaluation/search scaffolding (non-competitive baseline engine components).
  • Provide bindings/WASM targets for browser and polyglot tooling integration.

Project status

Active development. Current work is focused on building a correct, well-tested core for chess parsing, reconstruction, and analysis workflows before expanding engine-oriented capabilities.

License

Licensed under GPL-3.0-or-later. See LICENSE.

About

Fast Rust toolkit for PGN parsing, legal move generation, and chess game analysis.

Topics

Resources

License

Stars

Watchers

Forks

Contributors