### 36th KOSEN Programming Contest (Procon) – Competition Division (“En” Pairing) Quick Notes
- Field: even-sized square grid (size 4–24). Each cell has an integer entity; every value appears exactly twice. Values range 0 to (size²/2 – 1). Coordinates: top-left is (0,0).
- Pair: two identical values adjacent in 4-neighborhood (vertical or horizontal). Goal: maximize number of pairs.
- Move (“guidance”): choose an n×n square region (“en”, 2 ≤ n ≤ size) fully inside the field, rotate it 90° clockwise. Each rotation counts as one move.
- Problem JSON (distributed at start): `{"startsAt": <unix>, "problem": {"field": {"size": <even>, "entities": [[...], ...]}}}`. Before start, `"problem": null`.
- Answer JSON (client submission): `{"ops": [{"x": <left>, "y": <top>, "n": <side>}, ...]}`. Any invalid op (out of bounds or bad size) invalidates the whole answer.
- Match flow: size announced pre-match; server sends problem at start; teams submit within ~5 minutes; up to 30 submissions accepted (last valid counts).
- Scoring priority: (1) more pairs, (2) fewer moves, (3) earlier final submission; ties may be broken randomly.

### Local tooling
- `procon_tool.py generate --size <even> --moves <k> [--seed N] [--scramble-dir {cw,ccw}] --output puzzle.json --ops-out ops.json`: create a solved board, scramble with legal rotations (CW default, optional CCW), and save puzzle JSON. Ops file records the scramble direction plus ops list.
- `procon_tool.py serve -i puzzle.json [--ops-input ops.json] --port 8000`: serve a saved puzzle over HTTP at `/` (and `/ops` if provided).
- `procon_tool.py view -i puzzle.json`: print the puzzle grid to console.

### Solver v1 (C) plan (solver/v1/)
- Goal: fast baseline that returns short solutions; optimal on small boards if feasible, heuristic on larger boards.
- State: `uint8_t board[24][24]`, size, cached pair count; optional Zobrist hash. Apply/undo rotations in-place.
- Moves: all legal (x,y,n) with 2 ≤ n ≤ size, x ∈ [0,size-n], y ∈ [0,size-n]; optionally restrict n-set to limit branching.
- Heuristic: favor higher pair count; penalize broken pairs; optional proximity term (Manhattan distance between each value’s two cells). Move ordering by pair delta.
- Search strategy: small boards → A*/IDA* for optimal; larger boards → beam search (width/depth tunable). Keep best-so-far and respect time/expansion limits.
- I/O: read contest puzzle JSON; output `{"ops":[{"x":...,"y":...,"n":...},...]}`. Config flags: beam width, depth, move-set, time limit, strategy mode.
- Layout: `main.c` (CLI, strategy), `board.h/.c` (state/apply/undo/pairs), `search.h/.c` (A*/IDA*/beam), `json.c` (minimal parser), `Makefile`.

### Solver v2 (planned, solver/v2/) – speed/accuracy upgrades
- Search improvements:
  - Iterative beam (layered) with widening/winnowing: start narrow, widen if stagnating; shrink if explosion.
  - Hybrid: shallow optimal A*/IDA* for small n-limited moves + beam for deeper; or meet-in-the-middle on subregions.
  - Transposition table with Zobrist hashing to drop duplicates and keep best depth/score.
  - Move pruning: reduce n-set adaptively; skip rotations with zero delta-pairs if time is tight; symmetry cuts (rot/flip) when board allows.
  - Heuristics: weighted sum of pairs, proximity (Manhattan), cluster compactness, “potential pairs” estimate; optional ML-guided move ordering (lightweight).
- Parallelism:
  - Multi-threaded beam front expansion: split frontier among threads with lock-free or sharded queues; combine top-K.
  - Optional parallel Monte Carlo rollouts per node for move ordering.
  - CPU-only portable threads (std::thread or C11 threads); no OS-specific APIs.
- Time/quality controls:
  - Wall-clock budget flag; stop with best-so-far.
  - Adaptive depth based on progress (if no improvement in N layers, adjust move set or terminate).
  - Optional “explore” vs “fast” profiles (width/depth/hash size presets).
- Data/layout optimizations:
  - Tight board packing, preallocated node pools, memcpy-free apply/undo (in-place rotate with saved block).
  - Incremental pair delta updates instead of full recount.
  - Precompute all legal moves for given size; cache rotated index maps for speed.
- I/O/features:
  - Optional output of score trajectory; include hash table stats; deterministic seed control for randomized ordering if used.
  - CLI to choose strategy: `--mode optimal-small | beam | hybrid`, thread count, hash size, width/depth, move set.
