aboutsummaryrefslogtreecommitdiff
path: root/CLAUDE.md
diff options
context:
space:
mode:
Diffstat (limited to 'CLAUDE.md')
-rw-r--r--CLAUDE.md2
1 files changed, 1 insertions, 1 deletions
diff --git a/CLAUDE.md b/CLAUDE.md
index bae782b..bf8e2ac 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -41,7 +41,7 @@ The toolchain comes from a Nix flake (`flake.nix`, loaded via direnv `.envrc` â†
- `src/network.rs` — `Network`, a small MLP (52 inputs → 64 ReLU → 32 ReLU → tanh, positive favours tigers) with hand-written backprop and an `Adam` optimiser, all in one flat `params` Vec at the `W1`/`B1`/… offsets. Inputs are only the raw position: a bit per point for tigers and for sheep, sheep in hand / 20, and whether tigers are to move. `forward` adds up the layer-1 weight rows of the set bits rather than multiplying through the zeros. Also `Rng` (xorshift64*) and `Sample` (board, turn, target). File format (`save`/`load`): `TSNN`, then version, inputs, hidden1, hidden2 as little-endian u32s, then every param as a little-endian f32; changing the layer sizes makes old files fail to load.
- `src/neural-player.rs` — `NeuralPlayer`, a `MinimaxPlayer` like `ClaudePlayer` whose `evaluate` is a `Network`.
- `src/train.rs` — self-play training. Each generation plays `games_per_generation` games of the net against itself at a fixed depth (default 3) across all cores. Moves are random for the first `random_plies`, and with chance `epsilon` after that. A game reaching `ply_cap` is a draw, since the rules have no draw. Each position is labelled with a TD(λ) target worked backwards from the result (±1, or 0) through the searched scores. A position where a random move was played is labelled with its own search score instead, which cuts the chain there. Without that cut, the sheep's random moves (which usually hang a sheep) taught the net that tigers nearly always win. Self-play still ends mostly in tiger wins, because of those random moves, so judge progress by the match against `ClaudePlayer` (`match_games` = 100). The net then trains on the last `buffer_generations` generations, each position shown in a random one of the board's 8 symmetries (`GameBoard::transformed`). With `balance_outcomes` (the default), `balanced` builds each epoch from as many positions of sheep-win games as of tiger-win games: their mean, so the epoch stays the same size. Tiger-win positions are subsampled and sheep-win ones repeated; draws are kept as they are. The output shows the mean error on tiger-win (T) and sheep-win (S) positions separately, before and after training. After that it plays matches against the previous generation and against `ClaudePlayer`, which is only a yardstick and never a training signal. Each generation is saved as `out_dir/gen-NNN.bin` and `latest.bin`, and a rerun carries on from the newest `gen-NNN.bin`. `Config::from` (`--from`) starts from any weights file instead. Generation numbers still follow on from the out dir. The Adam state and the sample buffer are not saved, so they start empty either way.
-- `src/main.rs` — `bench [depth]` runs the benchmark; `train [generations] [games per generation] [out dir] [--from <weights>]` trains a network (use `--release`; `--from` may go anywhere); `neural <weights> [sheep|tiger]` plays you, on that side (default sheep), against a `NeuralPlayer`; otherwise it plays a game in the TUI (the sheep player first, then the tigers) and prints the winner. Which players it uses changes: `LocalPlayer` or `ClaudePlayer` on either side.
+- `src/main.rs` — the command line, parsed with clap's derive API (`Cli`, `Command`, `PlayArgs`, `TrainArgs`). With no command, or `play`, it plays a game in the TUI and prints the winner; `--sheep`/`--tiger` take `human`, `claude` or a weights file (`parse_player` → `PlayerKind`, turned into a `Box<dyn Player>` by `make_player`), and `--time` is each computer player's time limit in seconds. `neural <weights> [sheep|tiger]` is shorthand for you against a `NeuralPlayer`. `bench [depth]` runs the benchmark. `train [generations] [games] [out dir]` trains a network (use `--release`); every other `train::Config` field is a `--long-option` whose default is read from `Config::default()`, so keep `TrainArgs` and its `From` impl in step with `Config`.
Notation (`pos_name`, `impl Display for Move` in board.rs): files `a`–`e` are x 0–4, ranks are `5 - y` (y = 0 is drawn at the top as rank 5). Moves are `sc3` (place), `sc3c2` (sheep move), `ta5b4` (tiger step), `ta5xc3` (tiger jump).