v0.2.0 transitioned to api-only, extended and improved features, docs and tests added

This commit is contained in:
2025-10-29 23:28:19 -04:00
parent b98ea83012
commit 0ad608293e
32 changed files with 3683 additions and 1670 deletions

160
doc/api.md Normal file
View File

@ -0,0 +1,160 @@
# API Reference
Base URL: `http://localhost:8080/api/v1`
Content-Type: `application/json` (required for POST/PUT)
## Endpoints
### Create Game
`POST /games`
Creates new game with specified players.
**Request:**
```json
{
"white": {
"type": 1,
"level": 0,
"searchTime": 0
},
"black": {
"type": 2,
"level": 15,
"searchTime": 1000
},
"fen": "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"
}
```
- `type` (integer, required): 1=human, 2=computer
- `level` (integer, 0-20): AI skill level for computer players
- `searchTime` (integer, 100-10000ms): AI thinking time for computer players
- `fen` (string): Starting position in FEN notation (default: standard position)
**Response (201):**
```json
{
"gameId": "a1b2c3d4-e5f6-7890-1234-567890abcdef",
"fen": "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1",
"turn": "w",
"state": "ongoing",
"moves": [],
"players": {
"white": {"id": "...", "color": 1, "type": 1},
"black": {"id": "...", "color": 2, "type": 2, "level": 15, "searchTime": 1000}
}
}
```
### Get Game
`GET /games/{gameId}`
Returns current game state.
**Response (200):**
```json
{
"gameId": "...",
"fen": "...",
"turn": "w",
"state": "ongoing",
"moves": ["e2e4", "e7e5"],
"players": {...},
"lastMove": {
"move": "e7e5",
"playerColor": "b",
"score": 25,
"depth": 12
}
}
```
States: `ongoing`, `pending` (computer thinking), `white wins`, `black wins`, `draw`, `stalemate`
### Make Move
`POST /games/{gameId}/moves`
Submits human move or triggers computer move.
**Human move:**
```json
{"move": "e2e4"}
```
**Computer move trigger:**
```json
{"move": "cccc"}
```
Returns updated game state (200) or error (400).
### Undo Moves
`POST /games/{gameId}/undo`
Reverts moves from history.
**Request:**
```json
{"count": 2}
```
- `count` (integer, 1-300): Number of moves to undo (default: 1)
### Configure Players
`PUT /games/{gameId}/players`
Changes player configuration mid-game.
**Request:**
```json
{
"white": {"type": 2, "level": 5, "searchTime": 100},
"black": {"type": 1}
}
```
### Get Board
`GET /games/{gameId}/board`
Returns ASCII board visualization.
**Response (200):**
```json
{
"fen": "...",
"board": " a b c d e f g h\n8 r n b q k b n r 8\n..."
}
```
### Delete Game
`DELETE /games/{gameId}`
Removes game from memory. Returns 204 on success.
## Error Format
```json
{
"error": "Description",
"code": "ERROR_CODE",
"details": "Additional context"
}
```
Error codes:
- `GAME_NOT_FOUND` - Invalid game ID
- `INVALID_MOVE` - Illegal chess move
- `NOT_HUMAN_TURN` - Wrong player type for turn
- `GAME_OVER` - Game already ended
- `RATE_LIMIT_EXCEEDED` - Request limit exceeded
- `INVALID_REQUEST` - Malformed request
- `INVALID_CONTENT_TYPE` - Missing/wrong Content-Type header
## Rate Limiting
- Standard: 10 request/second/IP
- Development (`-dev`): 20 requests/second/IP
Exceeding limit returns 429 status.

61
doc/architecture.md Normal file
View File

@ -0,0 +1,61 @@
# Architecture
## Components
### Transport Layer (`internal/http`)
Fiber web server handling HTTP requests/responses. Implements routing, rate limiting, content-type validation, request parsing. Translates HTTP to internal Command objects.
### Processing Layer (`internal/processor`)
Central command handler containing business logic. Single `Execute(Command)` entry point decouples transport from logic. Uses synchronous UCI engine for validation, asynchronous EngineQueue for computer moves.
### Service Layer (`internal/service`)
In-memory state storage without chess logic. Thread-safe game map protected by RWMutex. Manages game lifecycle, snapshots, and player configuration.
### Supporting Modules
- **Engine** (`internal/engine`): UCI protocol wrapper for Stockfish process communication
- **Game** (`internal/game`): Game state with snapshot history
- **Board** (`internal/board`): FEN parsing and ASCII generation
- **Core** (`internal/core`): Shared types, API models, error constants
## Request Flow
### Human Move
1. HTTP handler receives `POST /games/{id}/moves` with UCI move
2. Creates MakeMoveCommand, calls `processor.Execute()`
3. Processor validates move via locked validation engine
4. If legal, gets new FEN from engine
5. Calls `service.ApplyMove()` to update state
6. Returns GameResponse
### Computer Move
1. HTTP handler receives `POST /games/{id}/moves` with `{"move": "cccc"}`
2. Processor sets game state to `pending`
3. Submits task to EngineQueue, returns immediately
4. Worker goroutine calculates move with dedicated Stockfish instance
5. Callback updates game state via service
6. Client polls for completion
## Concurrency
- **HTTP Server**: Fiber handles concurrent connections
- **Game State**: Single RWMutex protects game map (concurrent reads, serial writes)
- **Engine Workers**: Fixed pool (2 workers) with dedicated Stockfish processes
- **Validation Engine**: Single mutex-protected instance for synchronous validation
## Data Structures
### Game Snapshot
```go
type Snapshot struct {
FEN string
PreviousMove string
NextTurnColor Color
PlayerID string
}
```
### Command Pattern
Commands encapsulate operations with type and arguments, processed by single Execute method.
### Player Configuration
Players identified by UUID, configured with type (human/computer), skill level, and search time.

89
doc/development.md Normal file
View File

@ -0,0 +1,89 @@
# Development Guide
## Prerequisites
- Go 1.24+
- Stockfish in PATH
- Git
- curl, jq (for testing)
## Building
```bash
git clone https://git.lixen.com/lixen/chess
cd chess
go build ./cmd/chessd
```
## Running
### Flags
- `-host`: Server host (default: localhost)
- `-port`: Server port (default: 8080)
- `-dev`: Development mode with relaxed rate limits
### Modes
```bash
# Production (1 req/s rate limit)
./chessd
# Development (10 req/s rate limit)
./chessd -dev
```
## Project Structure
```
chess/
├── cmd/chessd/ # Entry point
├── internal/
│ ├── board/ # FEN/ASCII operations
│ ├── core/ # Shared types
│ ├── engine/ # Stockfish UCI wrapper
│ ├── game/ # Game state
│ ├── http/ # Fiber handlers
│ ├── processor/ # Command processing
│ └── service/ # State management
└── test/ # Test scripts
```
## Testing
```bash
# Unit tests
go test ./...
# API tests (requires dev mode)
./chessd -dev &
./test/test-api.sh
```
Test script validates:
- Basic CRUD operations
- Computer move triggering ("cccc" mechanism)
- Pending state protection
- Rate limiting
- Input validation
- Error handling
## Configuration
### Fixed Values
- Engine path: `"stockfish"` (internal/engine/engine.go)
- Worker count: 2 (internal/processor/processor.go)
- Queue capacity: 100 (internal/processor/queue.go)
- Min search time: 100ms (internal/processor/processor.go)
### Validation Rules
- Player type: 1 (human) or 2 (computer)
- Skill level: 0-20
- Search time: 100-10000ms
- UCI moves: 4-5 characters ([a-h][1-8][a-h][1-8][qrbn]?)
- Undo count: 1-300
## Limitations
- No persistence (memory only)
- Hardcoded Stockfish path
- Fixed worker pool size
- No game history beyond current session

316
doc/stockfish-extended.md Normal file
View File

@ -0,0 +1,316 @@
# Stockfish UCI Protocol Reference
## UCI Protocol Overview
Universal Chess Interface (UCI) is a text-based protocol for communication between chess engines and GUIs. Commands are line-based with ASCII encoding.
## Initialization Sequence
```
→ uci
← id name Stockfish 16
← id author Stockfish developers
← option name Debug Log File type string default
← option name Threads type spin default 1 min 1 max 1024
← option name Hash type spin default 16 min 1 max 33554432
← [... more options ...]
← uciok
→ isready
← readyok
```
## Core UCI Commands
### Engine Identification
- `uci` - Initialize UCI mode, engine responds with options and `uciok`
- `quit` - Terminate engine process
### Synchronization
- `isready` - Synchronization command, engine responds `readyok` when ready
- `ucinewgame` - Clear hash tables and reset for new game
### Position Setup
```
position [fen <fenstring> | startpos] [moves <move1> ... <moveN>]
```
- `startpos` - Standard starting position
- `fen <fenstring>` - Custom position in FEN notation
- `moves` - Apply moves from position in UCI format (e.g., e2e4, e7e8q)
### Search Commands
#### Basic Search
```
go [searchmoves <move1> ... <moveN>] [ponder] [wtime <ms>] [btime <ms>]
[winc <ms>] [binc <ms>] [movestogo <n>] [depth <n>] [nodes <n>]
[mate <n>] [movetime <ms>] [infinite]
```
Parameters:
- `searchmoves` - Restrict search to specific moves
- `ponder` - Start pondering mode (thinking on opponent's time)
- `wtime/btime` - White/black time remaining (ms)
- `winc/binc` - White/black increment per move (ms)
- `movestogo` - Moves until next time control
- `depth` - Search to fixed depth
- `nodes` - Search fixed number of positions
- `mate` - Search for mate in N moves
- `movetime` - Search for fixed time (ms)
- `infinite` - Search until `stop` command
#### Search Control
- `stop` - Stop calculating and return best move
- `ponderhit` - Opponent played expected ponder move
### Engine Options
```
setoption name <option_name> [value <value>]
```
## Stockfish-Specific Options
### Search Parameters
- `MultiPV` (1-500): Number of principal variations to calculate
- `Skill Level` (0-20): Playing strength limitation
- `Contempt` (-100 to 100): Draw avoidance tendency
- `Analysis Contempt` (Off/White/Black/Both): Contempt perspective
- `Move Overhead` (0-5000ms): Time buffer for network/GUI delay
- `Slow Mover` (10-1000): Time management aggressiveness
- `UCI_AnalyseMode` (true/false): Optimization for analysis
- `UCI_Chess960` (true/false): Fischer Random Chess support
- `UCI_ShowWDL` (true/false): Show win/draw/loss probabilities
- `UCI_LimitStrength` (true/false): Enable ELO limitation
- `UCI_Elo` (1320-3190): Target ELO when strength limited
### Hash Tables
- `Hash` (1-33554432 MB): Transposition table size
- `Clear Hash`: Clear transposition table
- `Ponder` (true/false): Think during opponent's turn
### Hardware Configuration
- `Threads` (1-1024): Search threads (typically CPU cores)
- `Use NNUE` (true/false): Neural network evaluation
- `EvalFile` (path): Custom NNUE evaluation file
### Syzygy Tablebases
- `SyzygyPath` (path): Directory containing tablebase files
- `SyzygyProbeDepth` (1-100): Minimum depth for tablebase probing
- `Syzygy50MoveRule` (true/false): Consider 50-move rule
- `SyzygyProbeLimit` (0-7): Maximum pieces for probing
## Debug Commands
### Board Display
```
→ d
+---+---+---+---+---+---+---+---+
| r | n | b | q | k | b | n | r | 8
+---+---+---+---+---+---+---+---+
| p | p | p | p | p | p | p | p | 7
+---+---+---+---+---+---+---+---+
| | | | | | | | | 6
[...]
+---+---+---+---+---+---+---+---+
a b c d e f g h
Fen: rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1
Key: 8F8F01D4562F59FB
Checkers:
```
### Evaluation
```
→ eval
← Total evaluation: +0.25 (white side)
← [detailed NNUE evaluation breakdown]
```
### Performance Testing
```
→ bench [depth] [threads] [hash] [fenfile] [limittype] [evaltype]
```
Default: `bench 13 1 16 default depth mixed`
## Search Output Format
### Standard Info String
```
info depth <d> seldepth <sd> multipv <n> score <score> nodes <n>
nps <n> hashfull <n> tbhits <n> time <ms> pv <move1> ... <moveN>
```
Fields:
- `depth` - Current search depth
- `seldepth` - Selective search depth
- `multipv` - PV number (when MultiPV > 1)
- `score cp <n>` - Evaluation in centipawns
- `score mate <n>` - Mate in N moves (negative if being mated)
- `score lowerbound/upperbound` - Bound type in fail-high/low
- `nodes` - Nodes searched
- `nps` - Nodes per second
- `hashfull` - Hash table saturation (per mill)
- `tbhits` - Tablebase positions found
- `time` - Search time (ms)
- `pv` - Principal variation (best line)
- `currmove` - Currently searching move
- `currmovenumber` - Move number in root move list
- `string` - Free-form engine output
### Win/Draw/Loss Output (UCI_ShowWDL=true)
```
info depth 20 score cp 15 wdl 395 604 1
```
WDL values in per mill: win/draw/loss from current side's perspective.
### Multi-PV Example
```
setoption name MultiPV value 3
go depth 15
info multipv 1 depth 15 score cp 31 pv e2e4 e7e5 g1f3
info multipv 2 depth 15 score cp 20 pv d2d4 d7d5 g1f3
info multipv 3 depth 15 score cp 15 pv g1f3 g8f6 d2d4
```
## Best Move Output
```
bestmove <move> [ponder <move>]
```
- `bestmove` - Best move in UCI notation
- `ponder` - Expected opponent response for pondering
Special cases:
- `bestmove (none)` - No legal moves (checkmate/stalemate)
- `bestmove 0000` - Null move (analysis mode only)
## Advanced Analysis Techniques
### Infinite Analysis
```
position fen <position>
setoption name UCI_AnalyseMode value true
go infinite
[... engine thinks until stop ...]
stop
```
### Multi-PV Analysis
```
setoption name MultiPV value 5
position startpos moves e2e4 e7e5
go depth 20
```
### Mate Search
```
go mate 7 # Find mate in 7 moves or less
```
### Fixed Node Search
```
go nodes 1000000 # Analyze exactly 1M positions
```
### Search Move Restriction
```
position startpos
go searchmoves e2e4 d2d4 g1f3 # Only consider these moves
```
## Time Management
### Tournament Time Control
```
position startpos moves e2e4 e7e5
go wtime 300000 btime 300000 winc 2000 binc 2000 movestogo 40
```
5 minutes + 2 second increment, 40 moves to time control.
### Sudden Death
```
go wtime 60000 btime 60000 # 1 minute each, no increment
```
### Fixed Time Per Move
```
go movetime 5000 # Think for exactly 5 seconds
```
## Performance Tuning
### Analysis Optimization
```
setoption name Threads value 8
setoption name Hash value 4096
setoption name UCI_AnalyseMode value true
setoption name MultiPV value 1
```
### Rapid/Blitz Optimization
```
setoption name Move Overhead value 100
setoption name Slow Mover value 50
setoption name Threads value 4
```
### Endgame Optimization
```
setoption name SyzygyPath value /path/to/tablebases
setoption name SyzygyProbeDepth value 1
```
## Error Handling
Common error responses:
- `Unknown command: <cmd>` - Invalid UCI command
- `Illegal move: <move>` - Move not legal in current position
- `Invalid position` - FEN parsing failed
- `No such option: <name>` - Unknown engine option
## Protocol Extensions
### Chess960 (Fischer Random)
```
setoption name UCI_Chess960 value true
position fen <chess960_fen> moves <move1> ...
```
### Debug Logging
```
setoption name Debug Log File value debug.txt
setoption name Use Debug Log value true
```
### NNUE Evaluation
```
setoption name Use NNUE value true
setoption name EvalFile value nn-[hash].nnue
```
## Typical Usage Patterns
### Game Analysis
1. Set analysis mode and resources
2. Load position with game moves
3. Run infinite analysis
4. Stop and retrieve evaluation
### Opening Preparation
1. Set MultiPV to compare variations
2. Load opening position
3. Search to fixed depth
4. Compare evaluations of candidate moves
### Endgame Study
1. Configure tablebase paths
2. Load endgame position
3. Search for mate or optimal play
4. Verify with tablebase hits
### Engine Match
1. Reset with ucinewgame
2. Set time controls
3. Apply moves incrementally
4. Use ponder for thinking on opponent time

85
doc/stockfish.md Normal file
View File

@ -0,0 +1,85 @@
# Stockfish Integration
## UCI Protocol Implementation
### Connection Management
Engine process started via `exec.Command("stockfish")` with bidirectional pipes. Initialization sequence:
1. Send `uci` → await `uciok`
2. Send `isready` → await `readyok`
3. Engine ready for commands
### Commands Used
#### Position Setting
```
position fen <fen_string> [moves <move1> <move2> ...]
```
Sets board state for validation or search.
#### Move Search
```
go movetime <milliseconds>
```
Calculates best move with time constraint. Returns:
- `info depth X score cp Y pv ...` (evaluation info)
- `bestmove <move>` (final result)
#### Board State Query
```
d
```
Debug command returning board visualization and FEN. Used for move validation.
#### Configuration
```
setoption name Skill Level value <0-20>
```
Sets engine strength for computer players.
### Response Parsing
#### Search Results
```go
type SearchResult struct {
BestMove string // UCI format move
Score int // Centipawns or mate distance
Depth int // Search depth reached
IsMate bool // Checkmate detected
MateIn int // Moves to mate
}
```
Parse `info` lines for evaluation data, `bestmove` for move selection.
#### FEN Extraction
Parse `d` output for line starting with `Fen: ` to get canonical position.
### Application Usage
#### Synchronous Validation (Processor)
Single mutex-protected engine instance validates moves:
1. Set position with current FEN
2. Attempt move
3. Get new FEN via `d` command
4. Compare FENs to determine legality
#### Asynchronous Calculation (EngineQueue)
Worker pool with dedicated engines per worker:
1. Receive task with FEN and time limit
2. Configure skill level
3. Search for best move
4. Return result via callback
### Error Handling
- Timeout protection (2x search time + 1s buffer)
- Process lifecycle management with graceful shutdown
- Fallback to force kill if quit fails
- "(none)" bestmove indicates no legal moves (checkmate/stalemate)
### Performance Considerations
- Reuse engine instances across multiple games
- `ucinewgame` between games for cache clearing
- Separate engines for validation vs calculation to avoid contention
- Fixed worker pool prevents resource exhaustion