README.md

# Echecs

**A high-performance Chess Engine implemented in pure Elixir.**

[![CI](https://github.com/HEKPYTO/ECHECS/actions/workflows/ci.yml/badge.svg)](https://github.com/HEKPYTO/ECHECS/actions/workflows/ci.yml)

Echecs is a robust chess library designed for speed and correctness. It leverages advanced optimization techniques available on the BEAM virtual machine (Bitboards, Magic Bitboards, Integer packing, etc), making it suitable for high-throughput analysis and scalable applications.

## Features

*   **High Performance**: Process over **4,000 games per second** (benchmarked on M1 Pro).
*   **Pure Elixir**: No NIFs or external dependencies (C/Rust) required for core logic.
*   **Advanced Engine Architecture**:
    *   **Bitboards**: 64-bit integer representation for O(1) board operations.
    *   **Magic Bitboards**: Fast sliding piece attack generation.
    *   **Integer Move Encoding**: Zero-allocation move generation using packed 20-bit integers to minimize Garbage Collection.
    *   **Zobrist Hashing**: Efficient game state hashing for repetition detection.
*   **Standard Compliance**:
    *   **FEN**: Full Forsyth-Edwards Notation parsing and generation.
    *   **PGN**: Parsing and replay support for standard chess games.
*   **Complete Rule Implementation**: Castling, En Passant, Promotion, 50-move rule, and 3-fold repetition.

## Installation

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

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

## Quick Start

### Basic Game Loop

```elixir
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

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

Echecs.FEN.to_string(game)
```

### PGN Parsing

```elixir
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 is designed to be extremely memory-efficient. The `Echecs.MoveGen.legal_moves_int/1` function returns moves as packed integers instead of structs, which is ideal for tight loops or search algorithms (e.g. Minimax) where struct allocation overhead is significant.

### Internal Board Representation

The board is represented internally as a Tuple of integers (Bitboards) for maximum access speed on the BEAM. This allows the engine to query piece locations and attack maps in constant time.

## Testing & Benchmarks

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

### Run Unit Tests
```bash
mix test
```

### Run Integration Benchmark
To verify large-scale replay correctness on your machine:

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

### Run Engine Benchmarks
```bash
mix echecs.benchmark
```

### Regenerate the Magic Cache
```bash
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.

```bash
docker build -t echecs .

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