Skip to content

HEKPYTO/ECHECS

Repository files navigation

Echecs

A pure Elixir chess library focused on rule correctness and practical performance.

CI Hex.pm

Echecs is a chess library implemented entirely in Elixir. It aims to keep the public API straightforward while using a faster internal representation for move generation, legality checks, and perft-style traversal.

Internally, the engine uses bitboards, packed integer moves, precomputed attack tables, and a tuple-based board representation. Those choices keep the hot path compact on the BEAM without relying on NIFs or external native code.

Features

  • Pure Elixir: core move generation and rule handling stay in Elixir.
  • Bitboard-based engine: board state is tracked with 64-bit piece sets and precomputed attack tables.
  • Packed move format: internal move generation uses integers to reduce allocation in tight loops.
  • Standard chess support: legal move generation, FEN, PGN replay, castling, en passant, promotion, repetition, and the 50-move rule.
  • Benchmarkable internals: the repository includes perft and move generation benchmarks for regression tracking.

How It Works

The public interface centers on %Echecs.Game{}. That struct keeps the information needed for normal application use such as turn, castling rights, en passant state, clocks, and game history.

For engine work, the board is converted into an internal tuple of bitboards. Move generation operates on that tuple representation and uses precomputed attack data for kings, knights, pawns, and magic-bitboard lookups for sliding pieces.

Moves are represented internally as packed integers. That allows legality checks and perft traversal to stay on a lightweight path before moves are converted back into structs for the higher-level API.

Repetition detection and state transitions use Zobrist hashing so positions can be tracked efficiently without comparing full board states on every move.

Installation

Add echecs to your list of dependencies in mix.exs:

def deps do
  [
    {:echecs, "~> 0.1.4"}
  ]
end

Quick Start

Basic Game Loop

game = Echecs.new_game()

moves = Echecs.legal_moves(game)

from = Echecs.Board.to_index("e2")
to = Echecs.Board.to_index("e4")
{:ok, game} = Echecs.make_move(game, from, to)

Echecs.status(game)

Squares are 0-indexed from a8 = 0 through h1 = 63.

FEN Manipulation

game = Echecs.new_game("rnbqkbnr/pp1ppppp/8/2p5/4P3/8/PPPP1PPP/RNBQKBNR w KQkq c6 0 2")

Echecs.FEN.to_string(game)

PGN Parsing

pgn = "1. e4 e5 2. Nf3 Nc6 3. Bb5"
moves = Echecs.PGN.parse_moves(pgn)
final_game = Echecs.PGN.replay(Echecs.new_game(), moves)

Advanced Usage

Performance Considerations

Echecs.MoveGen.legal_moves_int/1 returns packed integer moves instead of structs. That is the lower-level API used by the faster internal paths and is useful when you need to iterate over many positions without extra allocation.

Internal Board Representation

The board is represented internally as a tuple of bitboards. This keeps access and updates inexpensive on the BEAM and matches the data layout used by the move generator and perft code.

Testing & Benchmarks

The engine is verified against large-scale replay validation from the Lichess database to ensure correctness and stability.

Run Unit Tests

mix test

Run Integration Benchmark

To verify large-scale replay correctness on your machine:

LICHESS_DB_PATH=path/to/file.pgn.zst mix test --include integration test/integration/lichess_db_test.exs

Run Engine Benchmarks

mix echecs.benchmark

Regenerate the Magic Cache

elixir scripts/generate_magic_cache.exs

Docker Support

Deploy or test in a consistent environment using the provided Docker image. The image automatically pre-generates the magic bitboard cache for faster startup.

docker build -t echecs .

docker run -it --rm echecs
iex> Echecs.new_game()

About

Elixir chess lib for legal move generation, FEN/PGN support, and game state management.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors