aboutsummaryrefslogtreecommitdiff

Building

Quick start

nix develop            # or let direnv do it: the repo's .envrc says `use flake`
cargo run --release    # play a game (computer against computer by default)
cargo test

Without Nix, any stable Rust toolchain from 1.87 on works (the code uses unsigned::is_multiple_of, stabilised in 1.87). The flake currently pins rustc 1.95.

rustup toolchain install stable
cargo run --release

Always use --release (or the profiling profile) for anything that searches or trains. A debug build searches many times slower, so the computer players reach much shallower depths in the same time limit and training takes hours longer.

The toolchain: Nix

File Purpose
flake.nix The real definition: the package and the dev shell
flake.lock Pins the exact revisions of the flake's inputs
.envrc use flake, so direnv enters the dev shell when you cd in
shell.nix, default.nix flake-compat shims, so nix-shell and nix-build work without flakes

Flake inputs

Input Used for
nixpkgs (26.05) Everything: rustc, cargo and the dev tools
naersk Builds the crate as a Nix package (defaultPackage = naersk-lib.buildPackage ./.), reading Cargo.lock so dependencies are fetched reproducibly
flake-utils eachDefaultSystem, so the package and shell exist for every common platform

What the dev shell provides

Tool Why it's there
cargo, rustc Building and testing
rustfmt Formatting (but see the note on style below)
clippy Lints: cargo clippy
rust-analyzer Editor support; the shell sets RUST_SRC_PATH so it can find the standard library's source
pre-commit Git hook runner, for anyone who sets up hooks
perf, samply Profiling the search (see Benchmarking and profiling)

nix build builds the release binary into ./result/bin/tigers-and-sheep-rs. This is also what the GitHub workflow in .github/workflows/build_nix.yml runs on every push. Note that .github is currently listed in .gitignore, so that workflow only exists locally and isn't committed.

Crate dependencies

The crate keeps its dependencies few. Everything else (the board, the search, the neural network, its optimiser, the random number generator, the weights file format) is written by hand.

Crate Version What it does here
ratatui 0.30 The terminal UI: layout, bordered panes, paragraphs and the Widget trait that BoardView and every Player implement. It re-exports crossterm, which the game uses through ratatui::crossterm for raw mode, mouse capture and reading key and mouse events. Don't add crossterm as a direct dependency: the re-export keeps the two versions in step.
clap 4.6, feature derive The command line (Cli, Command, PlayArgs, TrainArgs in main.rs), including --help text taken from the doc comments
rayon 1.12 Parallelism for training only: self-play games and matches run across all cores, and the network's gradient and loss are computed in parallel chunks. The game itself is single-threaded.

Cargo profiles

Profile Command Use
dev cargo build, cargo test Day-to-day development and tests
release cargo run --release Playing and training
profiling cargo build --profile profiling Release optimisations plus debug info, so profilers can show function names and source lines. The binary lands in target/profiling/.

Cargo features

Feature Effect
search-stats Counts nodes, leaves, cache probes and hits, cutoffs and more during the search, and makes bench print them. Without it the count! macro compiles to nothing, so it costs nothing.

Run the tests both with and without it when touching the search, since some code only exists in one configuration:

cargo test
cargo test --features search-stats

Running

cargo run --release -- --help
cargo run --release -- -S human -T claude --time 5      # you play sheep against ClaudePlayer
cargo run --release -- -S weights/latest.bin -T human   # a trained network plays sheep
cargo run --release -- train 50 500 weights             # train a network
cargo run --profile profiling -- bench 9                # time the search

The game needs a terminal that supports mouse reporting and Unicode box-drawing characters; any modern terminal emulator does. The board grows to fill whatever space the window gives it.

Generated files

Path What In git?
target/ Cargo's build output No
result Symlink to the nix build output No
weights/ Trained networks, gen-NNN.bin and latest.bin No
.direnv/ direnv's cache of the dev shell No

Code style

Tabs for indentation and braces on their own line (Allman style). A few trait-impl blocks use 4-space indentation. cargo fmt would reformat the whole crate to a different style, so only run it on a file you're happy to see restyled, never across the crate.