From 15bdaa5d550115d97be3f89126c924b49c10a70f Mon Sep 17 00:00:00 2001 From: Dylan Date: Mon, 19 Oct 2026 00:37:17 +1300 Subject: feat: Initial commit What works: - Minimax search - With a simple player claude designed - Manual player - Move generation - Board display What needs improvement: - Manual player - Game coordinator - Draw checking - Nix setup --- CLAUDE.md | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 CLAUDE.md (limited to 'CLAUDE.md') diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..29064ea --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,49 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project + +A Rust implementation of "Tigers and Sheep" (a Bagh-Chal–style hunt game) on a 5x5 point board. The crate/binary is still named `rust-hello` (leftover from the template), not `tigers-and-sheep`. + +## Environment & commands + +The toolchain comes from a Nix flake (`flake.nix`, loaded via direnv `.envrc` → `use flake`); `shell.nix`/`default.nix` are flake-compat shims. Enter with `nix develop` if direnv isn't active. + +- Build: `cargo build` +- Run: `cargo run` +- Test all: `cargo test` +- Single test: `cargo test move_tiger_diagonal_jump_kills_sheep` (any substring of the test name filters) +- Lint / format: `cargo clippy`, `cargo fmt` +- Nix package build (what CI runs in `.github/workflows/build_nix.yml`): `nix build` + +## Architecture + +- `src/board.rs` — all game logic and its unit tests (`#[cfg(test)] mod tests` at the bottom). +- `src/player.rs` — the `Player` trait (`pick_move(board, turn) -> Move`). Also the private `MinimaxPlayer` trait: implementors supply `evaluate` (positive favours tigers) and optionally `depth()`, and a blanket impl makes every `MinimaxPlayer` a `Player`. +- `src/game.rs` — `GameHandler::play_game(sheep_player, tiger_player)` runs the game loop. Sheep move first, and it returns the winning `Turn`. +- `src/local-player.rs` (module `local_player`, pulled in via `#[path]` because of the hyphen) — `LocalPlayer`, a human at the terminal: renders the board, lists legal moves, and parses a move number or coordinates from stdin. +- `src/main.rs` — plays a game between two `LocalPlayer`s and prints the winner. + +Win check: `check_win(turn)` is called with the side about to move, and true means the side that *just* moved has won. Tigers win once 5 sheep are dead (`sheep_count() + sheep_left() <= 15`); otherwise the side that just moved wins if the side to move has no legal moves. + +### Board representation (`GameBoard`) + +The board is two `u32` bitmasks, `tiger_mask` and `sheep_mask`. This encoding is non-obvious: + +- Point `(x, y)` maps to index `x + y*5` (0..24), and its bit is `1 << idx`. So board bits occupy the **low 25 bits** (`BOARD_MASK`), with `(0,0)` at bit 0. +- The **high 7 bits of `sheep_mask`** (from `SHEEP_COUNT_SHIFT = 25`) are not board points — they hold the count of sheep still in hand (starts at 20). `sheep_left()` reads it; `place_sheep` subtracts `ONE_SHEEP` (`1 << 25`) from `sheep_mask` directly. Killing a sheep does not change this count (it counts unplaced sheep, not living ones). +- `Pos = (u8, u8)` is `(x, y)`; out-of-range coordinates panic in `bit_idx`. +- Default layout: tigers in the four corners, 20 sheep in hand. + +### Rules as implemented + +- Movement follows board lines: orthogonal lines everywhere; diagonals only through points where `x + y` is even (`on_line`). +- Sheep: placed one at a time until none remain in hand; only then may they move one step along a line. +- Tigers: step one along a line, or jump two along a line over a sheep, which kills it. +- `check_move` returns `Err(MoveError::…)` for an illegal move; `make_move` runs it first and returns the error without touching the board. `make_move_unchecked` skips the checks (for moves from `get_moves`). `MoveError`'s `Display` gives a human-readable message. Tests assert on the specific `MoveError` variant. +- `bit_idx` still panics on out-of-range coordinates. + +## Code style + +Mostly tabs for indentation, with braces on their own line (Allman style). A few trait-impl blocks use 4-space indentation, and `cargo fmt` would reformat everything, so don't run it across the whole crate unless asked. -- cgit v1.3.1