﻿# Progress Report (English) - NihonJijo_Procon

Date: 2026-02-12

## 1) What is in this repo (current snapshot)

- `procon_tool.py`: Python utility to generate/scramble puzzles, serve them over HTTP, and print grids to console.
- `visualizer/`: Tkinter GUI to step through operations and highlight adjacent pairs.
- `solver/v1/`: C solver (beam search baseline) + minimal JSON loader.
- `puzzles/` and `Puzzle_*.json`: example puzzle inputs (contest JSON shape).
- `Solution_*.json`, `solution_*.json`: example/previous solver outputs.
- `36matsue_bosyuyokou.pdf`: reference document (not analyzed here).

Note: `solver/v2/` exists but is intentionally excluded from this report.

## 2) Puzzle format and rules (as implemented/assumed)

- Puzzle input (contest shape): `startsAt`, `problem.field.size`, `problem.field.entities`.
- Entities are treated as integers; solver assumes `size` is even and within 4..24.
- Score metric used by the solver: number of adjacent equal pairs (4-neighborhood), counting each adjacency once (right + down checks).
- Move: rotate an `n x n` sub-square 90 degrees clockwise.

## 3) Local tooling (Python)

### `procon_tool.py`

Implemented subcommands:

- `generate`
  - Builds a solved board (horizontal pairs), then scrambles it by applying legal rotations.
  - Writes puzzle JSON to `--output`.
  - Writes ops JSON to `--ops-out` with the shape `{ "direction": "cw|ccw", "ops": [...] }`.

- `serve`
  - Serves a saved puzzle JSON at `/`.
  - If `--ops-input` is provided, serves ops at `/ops`.

- `view`
  - Prints `size` and the entity grid.

Gotcha:
- `generate --scramble-dir ccw` records CCW ops. The contest move is CW, and both `visualizer/main.py` and `serve` ignore the `direction` field, so replaying such ops as-is will be incorrect unless converted.

## 4) Visualizer (Python + Tkinter)

File: `visualizer/main.py`

- Loads puzzle JSON and ops JSON.
- Steps forward by applying each op as a clockwise rotation.
- Steps backward by applying the inverse move (3x clockwise rotations).
- Highlights all cells that are part of at least one adjacent equal pair.

Assumptions/limits:
- Ops are assumed to be clockwise (no support for an ops `direction` field).

## 5) Solver v1 (C) - current behavior

Files:
- `solver/v1/main.c`: CLI, file I/O, writes `{ "ops": [...] }`.
- `solver/v1/json.c`: minimal/fragile JSON parsing for `size` and flattened `entities`.
- `solver/v1/board.c`: board copy, clockwise rotate, full pair recount.
- `solver/v1/search.c`: beam search.

### CLI

From `solver/v1/main.c`:

- `--input <puzzle.json>` (required)
- `--output <ops.json>` (optional; default stdout)
- `--width N` beam width (default 200)
- `--depth N` max depth (default 25)
- `--nlimit N` max rotation size considered (default 4)

### Beam search outline

- Enumerates moves `(x, y, n)` for `n = 2..min(size, nlimit)`.
- For each node, evaluates all moves but keeps only the top `MAX_CHILDREN_PER_NODE` (= 32) by immediate resulting `pair_count`.
- Expands those candidates into the next frontier.
- Frontier nodes are ranked by `score = pair_count * 1000 - path_len`.
- Tracks a global best solution; early-exits if it reaches the theoretical maximum (`size^2 / 2`).

### Notable limitations (current)

- Pair counts are recomputed from scratch after every move (no incremental delta).
- Candidate evaluation applies moves twice (once for scoring, again when generating the child node).
- No transposition table / duplicate pruning.
- Minimal JSON parsing (string scanning + integer scraping) is not robust to arbitrary JSON variations.
- No explicit wall-clock time budget; runtime is controlled indirectly via `(width, depth, nlimit)`.

## 6) Repository artifacts / examples

- Root-level `Puzzle_4By4.json`, `Puzzle_8By8.json`, `Puzzle_16By16.json` (inputs) and matching `Solution_*.json` (outputs).
- `puzzles/` contains additional puzzles and op logs (some include `"direction": "ccw"`).
- `solver/v1/build/` contains a CMake build directory and compiled binaries (already present).

## 7) Suggested next steps (still within “v1” scope)

1) Make ops direction consistent: either always output CW ops from the tool, or teach `visualizer/main.py` + `procon_tool.py serve` to respect `direction`.
2) Speed up move evaluation: avoid double-apply and/or implement incremental pair delta updates.
3) Add a `--time-ms` (or similar) budget to stop cleanly with best-so-far.
4) Improve input robustness (real JSON parsing, or at least stricter validation for `entities`).
