# EZ-Chess

**AI-Powered Chess Analysis SDK**

EZ-Chess is a Python SDK that combines the power of Stockfish with Large Language Models to provide human-readable chess analysis. Use it as a library in your own applications, or run the included GUI.

[![PyPI version](https://badge.fury.io/py/ez-chess.svg)](https://badge.fury.io/py/ez-chess)
[![Python](https://img.shields.io/badge/Python-3.10+-blue.svg)](https://python.org)
[![License](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)
[![Stockfish](https://img.shields.io/badge/Engine-Stockfish%2016+-orange.svg)](https://stockfishchess.org/)

---

## Table of Contents

- [Features](#features)
- [Installation](#installation)
- [Quick Start](#quick-start)
- [CLI Usage](#cli-usage)
- [SDK / Library Usage](#sdk--library-usage)
- [Configuration](#configuration)
- [LLM Setup](#llm-setup)
- [API Reference](#api-reference)
- [Examples](#examples)
- [Troubleshooting](#troubleshooting)
- [License](#license)

---

## Features

- **Full SDK** - Use individual components to build your own chess applications
- **GUI Application** - Complete chess interface with analysis panel and AI chat
- **AI Explanations** - Natural language explanations via Groq (cloud) or Ollama (local)
- **Stockfish Integration** - Professional-grade position analysis
- **PGN Support** - Load and analyze games from PGN files
- **Extensible** - All internal tools exposed for custom integrations

---

## Installation

### From PyPI

```bash
# Core package (Stockfish analysis only)
pip install ez-chess

# With local LLM support (Ollama)
pip install ez-chess[local]

# With cloud LLM support (Groq)
pip install ez-chess[cloud]

# With GUI support
pip install ez-chess[gui]

# Everything (recommended)
pip install ez-chess[all]
```

### From Source (Development)

```bash
# Clone the repository
git clone https://github.com/AnubhavChoudhery/EZ-Chess.git
cd EZ-Chess

# Create virtual environment
python -m venv venv

# Activate it
# Windows:
venv\Scripts\activate
# Linux/macOS:
source venv/bin/activate

# Install in editable mode with all dependencies
pip install -e .[all]

# Or install with dev dependencies for development
pip install -e .[all,dev]
```

---

## Stockfish Installation

**IMPORTANT:** EZ-Chess requires Stockfish chess engine to function. Stockfish binaries are **NOT** bundled with the pip package due to PyPI size limits.

### For Package Users (After `pip install ez-chess`)

Choose one of the following methods:

#### Option 1: System-Wide Installation (Recommended)

Install Stockfish system-wide and ensure it's accessible in your PATH:

**Windows:**
1. Download Stockfish from https://stockfishchess.org/download/
2. Extract `stockfish-windows-x86-64-avx2.exe` or similar
3. Rename to `stockfish.exe`
4. Add to PATH:
   ```powershell
   # Move to a permanent location
   Move-Item stockfish.exe C:\Program Files\Stockfish\stockfish.exe
   
   # Add to PATH (PowerShell as Admin)
   $env:Path += ";C:\Program Files\Stockfish"
   [Environment]::SetEnvironmentVariable("Path", $env:Path, [EnvironmentVariableTarget]::Machine)
   ```

**macOS:**
```bash
# Using Homebrew (easiest)
brew install stockfish

# Verify installation
which stockfish
```

**Linux (Debian/Ubuntu):**
```bash
sudo apt update
sudo apt install stockfish

# Verify installation
which stockfish
```

**Linux (Fedora/RHEL):**
```bash
sudo dnf install stockfish
```

#### Option 2: Manual Binary Placement

Copy Stockfish binary directly to the package installation:

**Windows:**
```powershell
# Download from https://stockfishchess.org/download/
# Extract stockfish-windows-x86-64-avx2.exe

# Copy to package location (replace <venv> with your virtual environment path)
Copy-Item stockfish-windows-x86-64-avx2.exe <venv>\Lib\site-packages\bin\stockfish-windows.exe

# Example for default virtual environment
Copy-Item stockfish-windows-x86-64-avx2.exe venv\Lib\site-packages\bin\stockfish-windows.exe
```

**macOS:**
```bash
# Download from https://stockfishchess.org/download/
# Extract stockfish-macos-m1 (Apple Silicon) or stockfish-macos-x86-64 (Intel)

# Copy to package location
cp stockfish-macos-* <venv>/lib/python3.*/site-packages/bin/stockfish-mac
chmod +x <venv>/lib/python3.*/site-packages/bin/stockfish-mac
```

**Linux:**
```bash
# Download from https://stockfishchess.org/download/
# Extract stockfish-ubuntu-x86-64-avx2 or similar

# Copy to package location
cp stockfish-ubuntu-* <venv>/lib/python3.*/site-packages/bin/stockfish-linux
chmod +x <venv>/lib/python3.*/site-packages/bin/stockfish-linux
```

#### Option 3: Environment Variable

Set `STOCKFISH_PATH` to point to your Stockfish binary:

**Windows:**
```powershell
$env:STOCKFISH_PATH="C:\path\to\stockfish.exe"

# Make it permanent
[Environment]::SetEnvironmentVariable("STOCKFISH_PATH", "C:\path\to\stockfish.exe", [EnvironmentVariableTarget]::User)
```

**macOS/Linux:**
```bash
export STOCKFISH_PATH="/usr/local/bin/stockfish"

# Add to ~/.bashrc or ~/.zshrc for persistence
echo 'export STOCKFISH_PATH="/usr/local/bin/stockfish"' >> ~/.bashrc
```

### For Development/Source Code Users

If you cloned the repository:

1. **Download Stockfish binaries** from https://stockfishchess.org/download/

2. **Place in the `bin/` folder**:
   ```
   bin/
   ├── stockfish-windows.exe  (Windows binary)
   ├── stockfish-linux        (Linux binary)
   └── stockfish-mac          (macOS binary)
   ```

3. **Make executable** (Linux/macOS):
   ```bash
   chmod +x bin/stockfish-linux bin/stockfish-mac
   ```

**OR** install system-wide (see Option 1 above).

### Verification

Test that Stockfish is accessible:

```bash
# Test system installation
stockfish
# Should open Stockfish CLI. Type 'quit' to exit.

# Test with EZ-Chess
EZ-Chess analyze "rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq - 0 1"
# Should show position analysis

# Or launch GUI
EZ-Chess run
```

If you see "Stockfish binary not found", review the installation steps above.

### Download Links by Operating System

| OS | Download | Binary Name |
|----|----------|-------------|
| **Windows** | [stockfish-windows-x86-64-avx2.exe](https://stockfishchess.org/download/) | Rename to `stockfish.exe` or `stockfish-windows.exe` |
| **macOS (Apple Silicon)** | [stockfish-macos-m1](https://stockfishchess.org/download/) | Rename to `stockfish` or `stockfish-mac` |
| **macOS (Intel)** | [stockfish-macos-x86-64](https://stockfishchess.org/download/) | Rename to `stockfish` or `stockfish-mac` |
| **Linux (Ubuntu/Debian)** | `sudo apt install stockfish` or [stockfish-ubuntu-x86-64-avx2](https://stockfishchess.org/download/) | Use as `stockfish` or `stockfish-linux` |
| **Linux (Fedora/RHEL)** | `sudo dnf install stockfish` | Use as `stockfish` |

---

## Quick Start

### Launch the GUI

```bash
# After pip install
EZ-Chess run

# Or use lowercase
ez-chess run
```

### Quick Analysis (Python)

```python
import ez_chess

# Get the best move for a position
fen = "rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq - 0 1"
best_move = ez_chess.get_best_move(fen)
print(f"Best move: {best_move}")  # e.g., "e5" or "c5"

# Get full analysis
analysis = ez_chess.analyze_position(fen)
print(f"Evaluation: {analysis['evaluation']:+.2f}")
print(f"Best move: {analysis['best_move']}")
print(f"Top moves: {analysis['top_moves']}")
```

---

## CLI Usage

EZ-Chess provides a command-line interface for quick analysis and GUI launch.

### Launch GUI

```bash
# Basic launch
EZ-Chess run

# With specific LLM mode
EZ-Chess run --mode local    # Use Ollama
EZ-Chess run --mode cloud    # Use Groq

# Load a PGN file on startup
EZ-Chess run --pgn my_game.pgn
```

### Analyze from Command Line

```bash
# Basic analysis
EZ-Chess analyze "rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq - 0 1"

# With custom depth
EZ-Chess analyze "FEN_STRING" --depth 20

# Ask AI a question about the position
EZ-Chess analyze "FEN_STRING" -q "What's the best plan for Black?"

# Output as JSON
EZ-Chess analyze "FEN_STRING" --json
```

### Configuration Commands

```bash
# Show current configuration
EZ-Chess config --show

# Show config file path
EZ-Chess config --path
```

### Help

```bash
EZ-Chess --help
EZ-Chess run --help
EZ-Chess analyze --help
```

---

## SDK / Library Usage

EZ-Chess exposes all its functionality as a Python SDK. Import and use individual components in your own applications.

### Core Classes

```python
from ez_chess import ChessEngine, BoardState, PGNGame

# Chess Engine - Stockfish wrapper
engine = ChessEngine()
analysis = engine.analyze("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1")
print(analysis)

# Board State - Position management with navigation
board = BoardState()
board.make_move("e4")
board.make_move("e5")
print(board.get_fen())
board.undo_move()

# PGN Parser - Load games from PGN files
game = PGNGame("my_game.pgn")
print(f"White: {game.white}")
print(f"Black: {game.black}")
for move in game.moves:
    print(move)
```

### Convenience Functions

```python
import ez_chess

# Quick position analysis
result = ez_chess.analyze_position(fen, depth=18, num_moves=3)

# Get just the best move
best = ez_chess.get_best_move(fen)

# Get just the evaluation
evaluation = ez_chess.evaluate_position(fen)

# Parse a PGN file
games = ez_chess.parse_pgn("games.pgn")

# AI explanation (requires local or cloud extras)
explanation = ez_chess.explain_position(fen, "What's the best plan?")
```

### AI Agent

```python
from ez_chess import get_agent

# Get an AI agent for natural language analysis
agent = get_agent(mode="local")  # or mode="cloud"

# Ask questions about a position
fen = "r1bqkb1r/pppp1ppp/2n2n2/4p2Q/2B1P3/8/PPPP1PPP/RNB1K1NR w KQkq - 4 4"
response = agent.analyze(fen, "What's the best move and why?")
print(response)

# Compare moves
response = agent.analyze(fen, "Compare Qxf7+ and Nc3")
print(response)
```

### Tools (For Custom LLM Integrations)

```python
from ez_chess.tools import (
    get_best_move_tool,
    move_quality_tool,
    move_comparison_tool,
    position_overview_tool,
    CHESS_TOOLS,  # List of all tools for LLM function calling
)

# Use tools directly
fen = "rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq - 0 1"

# Get best move analysis
result = get_best_move_tool(fen)
print(result)

# Evaluate a specific move
quality = move_quality_tool(fen, "e5")
print(quality)

# Compare two moves
comparison = move_comparison_tool(fen, "e5,c5")
print(comparison)

# Get position overview
overview = position_overview_tool(fen)
print(overview)

# Use CHESS_TOOLS with your own LLM
# CHESS_TOOLS is a list of LangChain tool objects
# Perfect for building custom agents
```

### Configuration

```python
from ez_chess import get_config, reload_config, AppConfig

# Get current configuration
config = get_config()
print(f"LLM Mode: {config.llm.mode}")
print(f"Engine Depth: {config.engine.depth}")

# Reload configuration from file
config = reload_config()

# Access nested config
print(f"Cloud Model: {config.llm.cloud.model}")
print(f"Local Model: {config.llm.local.model}")
```

---

## Configuration

EZ-Chess uses a `config.yaml` file for configuration. Create one in your project directory or the package will use defaults.

### Sample config.yaml

```yaml
# EZ-Chess Configuration
# ======================

# LLM Settings
llm:
  # Mode: "cloud" (Groq API) or "local" (Ollama)
  mode: "local"
  
  # Cloud LLM settings (used when mode is "cloud")
  cloud:
    provider: "groq"
    model: "llama-3.1-70b-versatile"
    api_key: ""  # Or set GROQ_API_KEY environment variable
    temperature: 0.3
    max_tokens: 1024
    timeout: 60
  
  # Local LLM settings (used when mode is "local")
  local:
    provider: "ollama"
    model: "qwen2.5:7b"
    temperature: 0.3
    num_ctx: 4096
    num_predict: 512
    timeout: 120

# Stockfish Engine Settings
engine:
  depth: 18
  threads: 4
  hash_mb: 256
  multipv: 3
  cache_enabled: true
  cache_size: 1024

# UI Settings (for GUI)
ui:
  theme: "dark"
  board_size: 560
  show_coordinates: true
  show_best_move_arrow: true
  show_threat_arrows: true

# Analysis Settings
analysis:
  auto_analyze: true
  analysis_delay_ms: 300
  show_top_moves: 3
  pv_depth: 6
```

### Environment Variables

| Variable | Description |
|----------|-------------|
| `GROQ_API_KEY` | Groq API key for cloud mode |
| `EZCHESS_MODE` | Override LLM mode ("cloud" or "local") |

---

## LLM Setup

### Option A: Cloud Mode (Groq) - Recommended

Groq provides fast, free LLM inference.

1. **Get API Key**: Sign up at [console.groq.com](https://console.groq.com/) (free)

2. **Set API Key**:
   ```bash
   # Environment variable (recommended)
   export GROQ_API_KEY="gsk_your_key_here"  # Linux/macOS
   $env:GROQ_API_KEY="gsk_your_key_here"    # Windows PowerShell
   
   # Or in config.yaml
   llm:
     mode: "cloud"
     cloud:
       api_key: "gsk_your_key_here"
   ```

3. **Available Models**:
   | Model | Speed | Quality |
   |-------|-------|---------|
   | `llama-3.1-70b-versatile` | Fast | Excellent |
   | `llama-3.3-70b-versatile` | Fast | Excellent |
   | `llama-3.1-8b-instant` | Fastest | Good |
   | `mixtral-8x7b-32768` | Fast | Great |

### Option B: Local Mode (Ollama) - Offline

Run LLMs locally with Ollama.

1. **Install Ollama**: Download from [ollama.com](https://ollama.com/download)

2. **Pull a Model**:
   ```bash
   # Recommended for most GPUs (5GB VRAM)
   ollama pull qwen2.5:7b
   
   # For lower-end hardware (2GB VRAM)
   ollama pull qwen2.5:3b
   
   # For high-end GPUs (10GB+ VRAM)
   ollama pull qwen2.5:14b
   ```

3. **Configure**:
   ```yaml
   llm:
     mode: "local"
     local:
       model: "qwen2.5:7b"
   ```

4. **Ensure Ollama is Running**:
   ```bash
   ollama serve  # Start the server if not running
   ```

---

## API Reference

### Main Module (`ez_chess`)

| Function | Description |
|----------|-------------|
| `analyze_position(fen, depth=18, num_moves=3)` | Full position analysis |
| `get_best_move(fen, depth=18)` | Get best move in SAN |
| `evaluate_position(fen, depth=18)` | Get evaluation in pawns |
| `explain_position(fen, question)` | AI explanation (requires LLM) |
| `parse_pgn(path)` | Parse PGN file |
| `get_agent(**kwargs)` | Get AI agent instance |
| `get_config()` | Get configuration |
| `reload_config()` | Reload configuration |
| `run_gui()` | Launch GUI application |

### ChessEngine

```python
engine = ChessEngine()
engine.analyze(fen, depth=18, multipv=3)  # Full analysis
engine.get_best_move(fen)                  # Best move only
engine.evaluate(fen)                       # Evaluation only
```

### BoardState

```python
board = BoardState(starting_fen=None)
board.get_fen()           # Current FEN
board.make_move(san)      # Make a move (e.g., "e4")
board.undo_move()         # Undo last move
board.get_legal_moves()   # List of legal moves
board.is_game_over()      # Check if game ended
```

### PGNGame

```python
game = PGNGame(pgn_path)
game.white            # White player name
game.black            # Black player name
game.result           # Game result
game.moves            # List of moves
game.get_position(n)  # Get FEN at move n
```

---

## Examples

### Build a Simple Analysis Bot

```python
import ez_chess

def analyze_game(pgn_path):
    """Analyze all positions in a game."""
    game = ez_chess.PGNGame(pgn_path)
    
    print(f"Analyzing: {game.white} vs {game.black}")
    print("=" * 50)
    
    for i, move in enumerate(game.moves):
        fen = game.get_position(i)
        analysis = ez_chess.analyze_position(fen)
        
        print(f"Move {i+1}: {move}")
        print(f"  Eval: {analysis['evaluation']:+.2f}")
        print(f"  Best: {analysis['best_move']}")
        print()

analyze_game("my_game.pgn")
```

### Create a Custom LLM Agent

```python
from ez_chess.tools import CHESS_TOOLS
from langchain_groq import ChatGroq

# Use EZ-Chess tools with your own LLM setup
llm = ChatGroq(model="llama-3.1-70b-versatile")
llm_with_tools = llm.bind_tools(CHESS_TOOLS)

# Now use in your own LangChain/LangGraph agent
```

### Batch Analysis Script

```python
import ez_chess
import json

def batch_analyze(positions):
    """Analyze multiple positions and save results."""
    results = []
    
    for fen in positions:
        analysis = ez_chess.analyze_position(fen)
        results.append({
            "fen": fen,
            "evaluation": analysis["evaluation"],
            "best_move": analysis["best_move"],
            "top_moves": analysis["top_moves"]
        })
    
    with open("analysis_results.json", "w") as f:
        json.dump(results, f, indent=2)
    
    return results

# Example usage
positions = [
    "rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq - 0 1",
    "rnbqkbnr/pppp1ppp/8/4p3/4P3/8/PPPP1PPP/RNBQKBNR w KQkq - 0 2",
]
batch_analyze(positions)
```

---

## Troubleshooting

### "Stockfish not found"

```bash
# Verify installation
stockfish  # Should open Stockfish CLI
# Type 'quit' to exit

# If not found, install it:
# Windows: Download from stockfishchess.org
# macOS: brew install stockfish
# Linux: sudo apt install stockfish
```

### "Groq API key required"

```bash
# Set environment variable
export GROQ_API_KEY="gsk_..."  # Linux/macOS
$env:GROQ_API_KEY="gsk_..."    # Windows PowerShell

# Or add to config.yaml
```

### "Ollama connection failed"

```bash
# Start Ollama server
ollama serve

# Verify it's running
ollama list
```

### "Model not found" (Ollama)

```bash
# Pull the model first
ollama pull qwen2.5:7b
```

### Import Errors

```bash
# Install missing extras
pip install ez-chess[all]

# Or specific extras
pip install ez-chess[local]  # For Ollama
pip install ez-chess[cloud]  # For Groq
pip install ez-chess[gui]    # For GUI
```

---

## Project Structure

```
ez-chess/
├── ez_chess/              # Main package
│   ├── __init__.py        # Public API exports
│   ├── cli.py             # CLI entry point
│   ├── core/              # Core modules
│   │   ├── engine.py      # Stockfish wrapper
│   │   ├── board_state.py # Board management
│   │   ├── pgn_parser.py  # PGN parsing
│   │   ├── agent.py       # LLM agent
│   │   └── config.py      # Configuration
│   ├── ui/                # GUI components
│   └── tools/             # LLM tools
├── src/                   # Source implementations
├── ui/                    # UI implementations
├── tests/                 # Unit tests
├── config.yaml            # Configuration file
├── pyproject.toml         # Package metadata
├── LICENSE                # MIT License
└── README.md              # This file
```

---

## Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

1. Fork the repository
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
3. Commit your changes (`git commit -m 'Add amazing feature'`)
4. Push to the branch (`git push origin feature/amazing-feature`)
5. Open a Pull Request

---

## License

MIT License - Copyright (c) 2026 Anubhav Choudhery and Jai Ansh Bindra

See [LICENSE](LICENSE) for full details.

---

## Acknowledgments

- **[Stockfish](https://stockfishchess.org/)** - World's strongest open-source chess engine
- **[python-chess](https://python-chess.readthedocs.io/)** - Chess library for Python
- **[LangChain](https://langchain.com/)** - LLM application framework
- **[Groq](https://groq.com/)** - Fast LLM inference
- **[Ollama](https://ollama.com/)** - Local LLM runtime

---

<p align="center">
  <b>Made by Anubhav Choudhery & Jai Ansh Bindra</b>
</p>
