3 Commits
Author SHA1 Message Date
cabinwandClaude Opus 5 83796804d0 feat(levels): gate on crossing points, and lay the campaign out as segments
trackShape moves the two drawing measurements into src so the sweep, the pool
build, the selector and the gallery share one definition. They are one property
seen twice: a chord joining opposite ports is a straight line, and two of those
in a cell always cross, which is why the filler that paired leftovers straight
across produced a board that is both all-straight and all-crossings.

Crossings per cell is now a gate at 1.0. Bending the leftover ports alone takes
the median from 2.36 to 0.93, so the gate costs a third of the candidates rather
than most of them, and it is the difference the boards were described by.

Selection gains --plan, an ordered list of segments each naming how many levels
it wants and of what kind. Depth quotas cannot express the shape this campaign
needs, because the two good things pull against each other: a crowded board
clears beautifully and caps at three turns, while a deep lock needs room and so
stays sparse — at five turns and eight pieces per orientation, 16 of 18
candidates fail the release gate. Sorting by depth would file every crowded
level first and every deep one last; segments alternate them deliberately, and a
plan is left in the order it was written rather than re-sorted.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 20:05:54 +08:00
cabinwandClaude Opus 5 4c4c250511 fix(levels): stop rejecting crowded boards for an endgame nobody measured
No level in this project is more than a third pieces — 13% to 28% across the
shipping fifty, and the thousand-level set that preceded it peaks at 32% with
exactly one level above 30%. Clearing a full board is the satisfying part of a
clearing game, and it has never been on offer.

It was not a design choice. deadTurnAudit walks the reachable state space with a
20000-state budget, and the endgame gate read its answer. Past about eleven
pieces that budget is gone long before the walk reaches any state with three
pieces left, so the audit returned `endgameMinOpen: null` — and the gate,
written `endgameMinOpen >= 2`, compared null and got false. Every denser level
was thrown out for a bad endgame that was never looked at. `exhausted` was right
there in the audit's return value and nothing consulted it.

Endgames are now enumerated outright rather than walked to: C(26,3) is 2600
subsets, so it finishes on any board this game will ever have. The statistic is
the SHARE of endgames that are tight, not the minimum over them, because a
minimum over more subsets falls for arithmetic alone — the same confound that
made doubleDead look eight times worse for deep levels when the rate was 2%
against 5%. By share, crowded boards are the better ones: worst 0.33% against
1.73% for sparse.

With the gate measuring something, density inverts. At eight pieces per
orientation: 44% density, 18 of 23 candidates passing the whole chain, and not
one failing the dead-turn gate. At two: 19% density, 9 of 23, with eleven
failing on dead turns. perTurn becomes a swept dial, and the hard piece ceiling
that truncated the placement schedule regardless of it is gone.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 19:04:46 +08:00
cabinwandClaude Opus 5 ce7f6d30cf feat(levels): gate the dead turn, and state the curve instead of hoping for it
Round 1 played all fifty levels and came back with the mechanics clean and one
complaint repeated across the reports: 短暂以为转错了方向 — a turn that changed
nothing. That one is mechanical rather than perceptual, so it can be gated.

The first attempt gated `doubleDead`, and it was wrong. That counts dead states,
which scales with the state space: three-turn levels have ~187 reachable stuck
states and five-turn ones ~739, so a raw count made deep levels look eight times
worse when the rate is 2% against 5%. It would have erased every level past
three turns — the opposite of the brief, where turning is the signature and is
not to be rationed. The gate is `maxDeadTurns`, the longest run of turns before
something opens, at 1: one beat of suspense, then a release. Eleven of the fifty
shipped at 2.

Selection could not express the curve either. Spreading picks evenly over the
ranked pool returns whatever the pool is made of, and the pool is 88%
three-turn, so no weighting moved the distribution off {3: 46}. A quota per
depth states the curve outright, deepest first so the scarce end picks before a
family cap is spent on levels the shallow end has hundreds of.

Same rule bot, both sets: blind rotations 0.24 → 0.12, worst blind streak 4 → 1,
decisions unchanged at 10.3. The same amount to do, half the wasted motion.
Rotation now runs 1.8 / 3.0 / 4.1 across the bands against 1.8 / 3.0 / 3.5.

Verdicts are keyed by the board rather than by its id, because a reselect
re-issues ids from the ordinal and `c50-01-v05` is not the same board before and
after — the review sheet was one reselect away from printing one level's verdict
under another's thumbnail.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 17:13:02 +08:00