The first tap (or SHUFFLE) loads the solved board and deals it with a Fisher-Yates pass driven by the free-running logistic-map RNG, so tap timing picks the board. A parity latch adds one swap of cells 1 and 2 when needed, so every deal is solvable. Tile moves and deal swaps share one cell-swap mechanism, cutting RAM from 56.4 kB (failed to start on the Orion) to 34.6 kB (runs). Adds deal checks to verify_logic.py --v2 and the hint label to the viewer. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
54 lines
3.1 KiB
Markdown
54 lines
3.1 KiB
Markdown
# aspirin
|
|
|
|
15-puzzle (sliding 1-15) for the Ontrol **Orion** (800x480), built only from stock Sedona kits
|
|
(`control`, `ontrolControl`, `ontrolOx`, `ontrolOrion`), so it runs on the stock simulator.
|
|
|
|
| App | What it does |
|
|
|---|---|
|
|
| `aspirin.sax` / `app-ORION-aspirin.zip` | Playable game: auto-shuffle at start, tap a tile next to the gap to slide it, SHUFFLE button, move counter, SOLVED! |
|
|
| `aspirin_solver.sax` / `app-ORION-aspirin_solver.zip` | Demo: shuffles 30 moves, then an auto solver plays one move per second until SOLVED! (it records the shuffle and replays the inverse moves) |
|
|
| `aspirinV2.sax` / `app-ORION-aspirinV2.zip` | Fixed cells: nothing moves, each cell shows its number on white, the empty cell takes the board colour. Tap to start deals a random solvable board |
|
|
|
|
## Run in the simulator
|
|
|
|
`simulatorLauncher.exe` → folder button → pick a `app-ORION-*.zip` → Start Simulator.
|
|
The simulator is headless; to watch the screen run `viewer\run_viewer.cmd`
|
|
(live view over SOX as `guest`, display only).
|
|
|
|
## Build
|
|
|
|
```bash
|
|
python build.py # gen .sax -> sedonac .sab -> launcher backup zips (all apps)
|
|
python verify_logic.py # offline scan-engine model test of the game
|
|
python verify_logic.py --solver
|
|
python verify_logic.py --v2
|
|
```
|
|
|
|
`gen_aspirin.py` holds layout, colours, shuffle length (`SHUFFLE_MOVES`) and solver delay
|
|
(`SOLVE_DELAY`); `gen_aspirinV2.py` generates V2. Paths to the Sedona install are at the top of `build.py`.
|
|
|
|
## How it works
|
|
|
|
- Each tile is a `PushButtonLabel` whose `x`/`y` are linked from logic, so tiles move.
|
|
- Tile state = offset from home cell held in `ADemux2` latches; blank cell = 3 - sum(offsets).
|
|
- A tile moves on a one-scan `OneShot` when it is next to the blank and touched (or picked
|
|
by the shuffle); it latches the blank's cell and the blank follows automatically.
|
|
- Shuffle uses a logistic-map RNG made of `Reset`/`Mul2` blocks; only legal moves, so always solvable.
|
|
- Solved = blank home and the weighted sum of tile offsets is 0 (rearrangement inequality).
|
|
|
|
### V2 (fixed cells)
|
|
|
|
- 16 `NumericSelectLabel` cells; `in` = the number held (0 = empty), text list ` ;1;2;...;15;`.
|
|
- `backgroundColor` is linked from logic: white for a number, board colour for the empty cell.
|
|
- State = 16 cell values in `ADemux2` latches (boot loads the solved board).
|
|
- One swap mechanism moves values: each scan at most one pair of cells (A, B) exchanges values.
|
|
A tile move swaps the touched cell with the blank (new touch only, and only when adjacent).
|
|
- No shuffle moves: the first tap (or SHUFFLE) deals. It loads the solved board, then a
|
|
Fisher-Yates pass swaps cell i = 15..2 with a random cell j <= i, one swap per scan
|
|
(~1.5 s). The logistic-map value is made ~uniform with a `Linearize` (arcsine CDF). The RNG
|
|
runs from boot, so tap timing picks the board. The blank starts in cell 16.
|
|
- Solvability: with the blank home, a deal is solvable iff it is an even permutation; a parity
|
|
latch counts real swaps and an odd deal gets one extra swap of cells 1 and 2.
|
|
- Solved = sum of i * value_i over cells 1..15 is 1240 (its unique maximum).
|
|
- Keep RAM in mind: the Orion failed to start a 56 kB build of V2; the current one is ~35 kB.
|