Reference · Rules, solvers and generation
SolveCounttype
THE TSUNAGI SOLVER: how many ways a layout can be joined, up to a limit, and how much trying it took.
Run where the levels are made (scripts/tsunagi-levels.ts) and in the
unit test that proves every shipped level has exactly one answer — never in
a browser and never on a request. A level is a line of data by the time
anybody plays it.
The rules it counts under are the published ones, and no more: a line runs
cell to cell across and down, never through a wall (steps.ts), lines never
cross or share a cell except on a bridge — where one goes straight across
and a different one straight down — a waypoint is taken by its own pair's
line and no other, on a board that wraps a line may leave one edge and come
back at the other, and every open cell and both ways over every bridge are
used. A line MAY run beside itself; the solver counts those
answers too, so "exactly one" is a claim about every answer the rules
allow, not only the tidy ones.
Search: each pair's line grows from its first stone towards its second. At every step the pair with the fewest ways on is grown (a pair with one is forced), after four checks that throw a hopeless grid away early:
- every empty cell still has two ways in and out (an empty cell or an unfinished line's end beside it), or no line could pass through it;
- every unfinished line's growing end and its far stone each have a way on;
- the growing end and the far stone touch one common region of empty cells (or each other), or the line can never close;
- every region of empty cells is touched at both ends by some unfinished line, or nothing could ever fill it.
Import it
import type { SolveCount } from "@johnmorrisdotca/tsunagi";
Definition
type SolveCount = {
count: number;
nodes: number;
branches: number;
solution: number[] | null;
solutions: number[][];
gaveUp: boolean;
};
Members
| Name | Type | Description |
|---|---|---|
count | number | Answers found, never more than the limit asked for. |
nodes | number | Positions looked at: the measure of how much trying the layout takes. |
branches | number | Positions where more than one way on had to be tried: the measure of guessing. |
solution | number[] | null | The first answer found, as the pair through each cell; null for none. |
solutions | number[][] | Every answer found, in the order found: a second one is where a generator mends a board that has two ( |
gaveUp | boolean | True when the search stopped at the node budget before it could say. |
Examples
import { TSUNAGI_4 } from "@johnmorrisdotca/tsunagi/levels-4";
import { countSolutions, decodeLayout } from "@johnmorrisdotca/tsunagi";
import type { SolveCount } from "@johnmorrisdotca/tsunagi";
const givens = TSUNAGI_4[0][0];
const layout = decodeLayout(givens,4)!;
const value: SolveCount = countSolutions(layout,2,20000);
console.log(value);{
count: 1,
nodes: 13,
branches: 0,
solution: [
0, 0, 0, 0, 1, 1,
1, 1, 2, 2, 2, 2,
3, 3, 3, 3
],
solutions: [
[
0, 0, 0, 0, 1, 1,
1, 1, 2, 2, 2, 2,
3, 3, 3, 3
]
],
gaveUp: false
}What it prints (run when this page was built)