Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
cd9c87f
chore: update .gitignore
SmilingWayne May 13, 2026
c98dcb4
feat: add DatasetPage component and routing, implement dataset puzzle…
SmilingWayne May 13, 2026
76012cc
refactor: remove preset library functionality and related tests, upda…
SmilingWayne May 13, 2026
aa9bd79
feat: implement slitherlink puzzle stats display and functionality, a…
SmilingWayne May 13, 2026
c366271
chore: add comprehensive guide
SmilingWayne May 13, 2026
2c25e1f
feat: new Live Stat window
SmilingWayne May 14, 2026
4dcc282
feat: Live Stat enhance
SmilingWayne May 14, 2026
c6d1f08
feat: enhance Live Stats with rule usage visualization and improved r…
SmilingWayne May 14, 2026
efb3a0d
feat: add Masyu puzzle support with import, rendering, and initial ru…
SmilingWayne May 16, 2026
88e6af5
chore: update Masyu ruleset
SmilingWayne May 16, 2026
5e4d1d9
feat: implement Masyu puzzle loading and rules, including default sam…
SmilingWayne May 16, 2026
7ecb556
feat: add deterministic Masyu solving rules and validation tests, inc…
SmilingWayne May 16, 2026
684da6a
feat: introduce new Masyu rules for loop prevention and black pearl c…
SmilingWayne May 16, 2026
9026364
feat: enhance Masyu puzzle completion analysis with new reporting str…
SmilingWayne May 17, 2026
fd276b2
feat: implement Masyu tile color propagation rules and integrate into…
SmilingWayne May 17, 2026
85f14ae
feat: add Masyu agent brief documentation
SmilingWayne May 17, 2026
143be4f
feat: implement Masyu Color-Line Propagation rule to enhance line mar…
SmilingWayne May 17, 2026
1e58213
feat: add Masyu Candidate Bridge Line and Tile Connectivity Cut Color…
SmilingWayne May 17, 2026
5e99beb
feat: introduce Black Pearl Strong Inference rule and Masyu Color-Pea…
SmilingWayne May 17, 2026
7f97fdc
chore: prep for release
SmilingWayne May 17, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ dist
dist-ssr
benchmark-results
playwright-report
.husky
.pnpm-store
test-results
dataset/private/
*.local
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# PuzzleKit Web

[PuzzleKit Web](https://smilingwayne.github.io/puzzlekit-web/) provides step-wise and explainable inference flow for logical puzzles (only slitherlink for now). The core goal is not just to output a final answer, but to make each deduction step explicit: what changed, why it changed, and which rule produced this change.
[PuzzleKit Web](https://smilingwayne.github.io/puzzlekit-web/) provides step-wise and explainable inference flow for logical puzzles, now supporting only slitherlink (with better perf) and Masyu (with poor perf). The core goal is not just to output a final answer, but to make each deduction step explicit: what changed, why it changed, and which rule produced this change.

Current focus:

Expand Down
166 changes: 166 additions & 0 deletions docs/ADDING_PUZZLE_FAMILY_EN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
# Adding a Puzzle Family

This guide is for developers and AI agents adding a new puzzle type such as
Nonogram or Masyu. Build a small vertical slice first: parse or create one
puzzle, render it, run a few explainable rules, and prove replay works.

PuzzleKit is a reasoning engine with a UI. Keep puzzle logic in `domain/`, keep
rendering/orchestration in `features/` and `app/`, and connect them through
`PuzzleIR` plus `PuzzlePlugin`.

---

## 1. Understand the Core Mechanisms

Read these before writing code:

- `src/domain/ir/types.ts` - shared `PuzzleIR`, cell/edge/sector/vertex state.
- `src/domain/ir/keys.ts` - stable keys for cells, edges, sectors, and vertices.
- `src/domain/rules/types.ts` - `Rule`, `RuleApplication`, `RuleStep`, and `RuleDiff`.
- `src/domain/rules/engine.ts` - applies and reverts rule diffs.
- `src/features/solver/solverStore.ts` - loads puzzles, runs plugin rules, replays steps with checkpoints, and builds terminal reports.
- `src/features/editor/editorStore.ts` - current editor state model and Slitherlink editing pattern.
- `src/domain/plugins/types.ts` and `registry.ts` - plugin boundary for puzzle families.
- `src/domain/benchmark/*` and `dataset/public/*` - dataset and benchmark flow.

Replay safety is the central contract. A rule must return explicit diffs; the
engine and solver store must be able to apply and undo those diffs without
hidden mutation. The solver now uses incremental replay plus periodic
checkpoints, so every puzzle family must keep `RuleDiff` forward and reverse
semantics deterministic.

---

## 2. Define the Puzzle Boundary

Start by deciding how the new puzzle maps into `PuzzleIR`:

- Use `cells` for clue values, fills, shaded states, or symbols.
- Use `edges` for line-like or wall-like decisions.
- Use `sectors` only when the puzzle needs Slitherlink-style corner constraints.
- Use `vertices` only when vertex candidate sets are part of the reasoning model.
- Put puzzle-specific metadata in `metadata`, but prefer typed shared fields when they fit.

Then add or update a plugin in `src/domain/plugins/`:

- `id` and `displayName`
- `parse(input)` for supported input
- `encode(puzzle)` when export is available
- `getRules()` in deterministic execution order
- optional `help`, `legend`, and `getStats(puzzle)` for UI affordances

Register the plugin in `src/domain/plugins/registry.ts`. Planned stubs are fine,
but do not make UI or docs imply a puzzle is implemented until it can parse,
render, and run at least a minimal rule path.

---

## 3. Build the First Vertical Slice

Recommended order:

1. **IR factory and parser**
- Add a puzzle factory similar to `createSlitherPuzzle` if blank puzzles are needed.
- Add parser tests with small, readable fixtures.
- If full URL support is too large, add a minimal loader path first and document the limit.

2. **Renderer**
- Add a puzzle-specific board renderer or make an existing renderer safely plugin-aware.
- Render actual puzzle state, not placeholder marketing UI.
- Keep dimensions stable so large boards and zoom do not shift layout.

3. **Rules**
- Add a puzzle-specific rule folder under `src/domain/rules/<puzzle>/`.
- Start with small deterministic rules that produce clear messages and explicit `RuleDiff`s.
- Keep rule order in one aggregation file, like Slitherlink's `rules.ts`.

4. **Solver integration**
- Ensure `getRules()` returns the new ordered rules.
- Add replay tests proving `nextStep`, `prevStep`, small `goToStep` moves, and large checkpoint-backed `goToStep` jumps rebuild the same state.
- Add terminal/completion analysis when the puzzle has a meaningful solved/stalled report.

5. **Editor and export**
- Add editor tools only after parsing/rendering/rules are stable.
- Keep editor state normalized as `PuzzleIR` so it can load directly into the solver.
- Add export only for formats that can round-trip reliably.

6. **Dataset and benchmark**
- Add small public fixtures only when they are useful and stable.
- Use private datasets for local experiments.
- Benchmark reports should summarize status, step count, timing, and rule usage.

---

## 4. UI Integration Checklist

For a puzzle family to feel first-class, decide which of these it owns:

- Solver board rendering and highlights.
- Live Stats coverage semantics for its chosen IR fields.
- Editor board rendering and input tools.
- Puzzle type controls in Solver, Editor, and Dataset pages.
- `PuzzleInfoButton` content via plugin `help`.
- `BoardLegendButton` content via plugin `legend`.
- Board-title statistics via plugin `getStats`.
- Dataset preview rendering.
- Export controls and error messages.

Prefer plugin-aware shared components when the behavior is generic. Prefer
puzzle-specific components when the interaction model is genuinely different
from Slitherlink.

Live Stats currently derives board progress and coverage from common IR fields
such as decided edges, filled cells, and narrowed vertices. If a new puzzle uses
different state primitives, either make those primitives fit the shared
coverage model or add a small plugin-aware adapter before presenting the stats
as meaningful.

---

## 5. Suggested Roadmap

**Milestone 1: Parse, render, sample puzzle**

- A sample puzzle can load through the plugin.
- The board displays the puzzle accurately.
- Tests cover parser basics and rendering smoke behavior.

**Milestone 2: Deterministic starter rules**

- Add a small ordered rule set.
- Each rule returns explainable messages and explicit diffs.
- Replay tests prove forward/backward timeline behavior, including timeline jumps.
- Live Stats shows sane active-prefix counts for the generated trace.

**Milestone 3: Editor and export**

- Add minimal editor tools for the puzzle's givens and user-editable state.
- Solver can load the editor puzzle without conversion hacks.
- Export round-trips when supported.

**Milestone 4: Completion, datasets, UI polish**

- Add solved/stalled analysis for terminal reports.
- Add curated public dataset entries and benchmark coverage.
- Add help, legend, and stats where they clarify the puzzle.

**Milestone 5: Stronger inference**

- Add advanced or branch-based inference only after deterministic rules are stable.
- Inject deterministic rule dependencies instead of self-referencing exported rule arrays.
- Keep branch reasoning conservative and test contradiction cases carefully.

---

## 6. Implementation Cautions

- Do not put puzzle-specific rules into shared solver orchestration.
- Do not mutate puzzle state inside a rule; return `RuleDiff`s.
- Do not change diff semantics without updating engine behavior, checkpoint replay, and replay tests.
- Do not hide non-determinism behind rule ordering or object iteration.
- Do not rely on object identity or hidden mutation for replay or stats; caches may be reused across timeline browsing.
- Do not overfit UI to Slitherlink if the next puzzle needs different primitives.
- Do not claim full support in docs, dropdowns, or datasets until parse/render/solve basics exist.

The best first version is small, explainable, and replay-safe. Coverage can grow
incrementally once that spine is solid.
148 changes: 148 additions & 0 deletions docs/MASYU_AGENT_BRIEF.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
# Masyu Agent Brief

This is the lightweight starting point for AI agents working on Masyu in PuzzleKit Web. Read this first. Only open the longer docs if the task needs them.

## Read-On-Demand Route

- Implement a Masyu rule: read this brief, then inspect the relevant `src/domain/rules/masyu/*` files.
- Research Puzzlink Assistance strategy: also read `docs/MASYU_ASSIST_STRATEGIES_CN.md`.
- Design a new rule family: also read `docs/MASYU_RULE_ABSTRACTIONS.md`.
- Check historical context: also read `docs/MASYU_CHANGELOG.md`.
- Change plugin, IR, replay, stats, or app-wide architecture: also read `docs/PROJECT_GUIDE_EN.md`.

## Current State

Masyu is implemented as a first-class puzzle family with import, rendering, replay-safe rules, completion analysis, and tile-color topology support.

Canonical model:

- `PuzzleIR.cells`: pearl clues, stored as `{ kind: "pearl"; color: "white" | "black" }`.
- `PuzzleIR.lines`: canonical Masyu loop decisions. These are center-to-center line segments between orthogonally adjacent cells.
- `PuzzleIR.tiles`: vertex-centered region-color units for Masyu inside/outside reasoning.
- `PuzzleIR.edges`: Slitherlink edge state. Do not use it as Masyu loop state.

Important coordinate convention:

- Cell keys are `row,col`, zero-based.
- Masyu line keys connect cells: `lineKey([r, c], [nr, nc])`.
- Masyu tile keys are grid vertices: `tileKey(row, col)` where `row = 0..rows`, `col = 0..cols`.

## Current Rule Stack

Registered rule order:

1. `White Circle Rule`
2. `Black Circle Rule`
3. `Black Facing Consecutive Whites`
4. `Black Diagonal White Pinch`
5. `Consecutive White Pearls Straight`
6. `Double Black Squeeze`
7. `Masyu Tile Color Propagation`
8. `Masyu Color-Pearl Propagation`
9. `Masyu Color-Line Propagation`
10. `Masyu Tile Connectivity Cut Coloring`
11. `Masyu Candidate Bridge Line`
12. `Prevent Premature Loop`
13. `Black Pearl Candidate Pruning`
14. `Pearl Completion`
15. `Cell Completion`
16. `Black Pearl Strong Inference`

Implemented rule areas:

- Pearl-local rules for white straight-through and black turn/extension behavior.
- Local pattern rules derived from common Masyu situations.
- Premature loop prevention over `PuzzleIR.lines`.
- Black pearl candidate pruning with shallow feasibility checks.
- Black pearl strong inference with bounded trial propagation that crosses out an exit when that exit's two-step assumption leads to a hard contradiction.
- Completion rules for pearl and non-pearl cells.
- Tile color propagation:
- boundary tiles are `yellow` / outside;
- known `blank` lines imply same-color adjacent tiles;
- known `line` lines imply opposite-color adjacent tiles;
- white pearl diagonal tiles imply opposite colors;
- same-color adjacent tiles imply a `blank` Masyu line;
- opposite-color adjacent tiles imply a `line` Masyu line;
- tile connectivity cuts color articulation regions needed to connect known inside/outside regions;
- regions unreachable from outside/yellow through non-line passages become inside/green;
- tile fills are replay-safe via `TileDiff`;
- Masyu tile colors render on the board as full-size vertex-centered tiles.

## Architecture Hotspots

Use these files first:

- Masyu rule registration: `src/domain/rules/masyu/rules.ts`
- Masyu geometry helpers: `src/domain/rules/masyu/rules/shared.ts`
- Pearl rules: `src/domain/rules/masyu/rules/pearls.ts`
- Pattern rules: `src/domain/rules/masyu/rules/patterns.ts`
- Loop rules: `src/domain/rules/masyu/rules/loop.ts`
- Tile color rules: `src/domain/rules/masyu/rules/color.ts`
- Tile connectivity rules: `src/domain/rules/masyu/rules/connectivity.ts`
- Candidate bridge rules: `src/domain/rules/masyu/rules/bridges.ts`
- Lookahead helpers: `src/domain/rules/masyu/rules/lookahead*.ts`
- Tests: `src/domain/rules/masyu/rules.test.ts`

Replay and rendering plumbing:

- Rule diffs: `src/domain/rules/types.ts`
- Diff application: `src/domain/rules/engine.ts`
- Board rendering: `src/features/board/CanvasBoard.tsx`
- Solver timeline/highlights: `src/features/solver/solverStore.ts`

## Current Development Direction

Near-term Masyu work should focus on making tile color useful beyond connectivity coloring:

1. Add pearl-local color implications:
- migrate selected Puzzlink in/out tricks only when they can be explained as small Masyu tile parity rules.

2. Keep rule granularity small:
- one reasoning idea per rule;
- explicit diffs;
- concise explanation message;
- focused fixture tests.

## How To Start A Task

Default workflow:

1. Read this brief.
2. Inspect the exact rule/helper files touched by the task.
3. Search existing tests before writing a new rule.
4. Prefer extending local Masyu helpers over copying Slither code directly.
5. Run focused tests first, then build.

Useful commands:

```bash
pnpm test:run src/domain/rules/masyu/rules.test.ts
pnpm test:run src/domain/rules/engine.test.ts src/features/solver/solverStore.test.ts
pnpm build
```

## When To Read More

Read `docs/MASYU_RULE_ABSTRACTIONS.md` when designing a new rule family or checking intended rule taxonomy.

Read `docs/MASYU_ASSIST_STRATEGIES_CN.md` only when tracing a deduction back to Puzzlink Assistance. It is research/provenance, not the implementation source of truth.

Read `docs/MASYU_CHANGELOG.md` only when historical context matters.

Read `docs/PROJECT_GUIDE_EN.md` when changing plugin contracts, IR conventions, replay, stats, or app-wide architecture.

## Maintenance Rules

- Update this brief whenever rule order, canonical state, or next development direction changes.
- Keep this brief current, not historical. Move history to `docs/MASYU_CHANGELOG.md`.
- Keep this brief short enough that it can be pasted into an AI context without drowning the actual task.
- Prefer links and routing over duplicating long explanations.

## Guardrails

- Do not use `PuzzleIR.edges` for Masyu loop deductions.
- Do not mutate `PuzzleIR` inside rule inspection.
- Do not batch unrelated reasoning into one rule.
- Do not overwrite already-decided line/tile state with the opposite value.
- Do not make long Puzzlink-style monolithic rules; keep steps explainable.
- If a doc disagrees with current code, trust current code and update this brief.
Loading
Loading