function armsOf
armsOf(mask: number): number
How many sides a piece opens on.
@johnmorrisdotca/suido 1.3.0 · 20 entry points · 149 exports
@johnmorrisdotca/suido 79@johnmorrisdotca/suido/draw 10@johnmorrisdotca/suido/play 11@johnmorrisdotca/suido/element 1@johnmorrisdotca/suido/element/define 0@johnmorrisdotca/suido/levels 33@johnmorrisdotca/suido/levels-5x5 1@johnmorrisdotca/suido/levels-6x6 1@johnmorrisdotca/suido/levels-7x7 1@johnmorrisdotca/suido/levels-8x8 1@johnmorrisdotca/suido/levels-9x9 1@johnmorrisdotca/suido/levels-10x10 1@johnmorrisdotca/suido/levels-11x11 1@johnmorrisdotca/suido/levels-12x12 1@johnmorrisdotca/suido/levels-13x13 1@johnmorrisdotca/suido/levels-14x14 1@johnmorrisdotca/suido/levels-5x7 1@johnmorrisdotca/suido/levels-6x10 1@johnmorrisdotca/suido/levels-8x14 1@johnmorrisdotca/suido/marks 2@johnmorrisdotca/suidoarmsOf blendOf canTurn canTurnAt cellChar checkSuidoAnswer countSolutions decodeLayout deduce Deduction DIFFICULTY_SIDES DIFFICULTY_WEIGHTS difficultyOf EAST encodeLayout exactDifficultyOf exactScoreOf Flow flowOf flowOfGame Game gameCode gameFromProgress gameProgress hintFor isGameSolved isLocked isSolved isTwisted Kind Layout laySuido Made MadeScored MakeOptions makeSuido makeUnscored MAX_SIDE Measure MEASURE_NAMES MeasureName measureSuido neighboursOf newGame NORTH opposite percentileIn quantilesOf quartersBetween Random Reference referenceFor referenceKey rotationsOf scoreOf seededRandom Shape SHAPE_MASKS shapeOf shuffled SIDE_STEPS SIDES solve SolveResult SOUTH SUIDO_TWISTS SuidoCheck symmetryKey tapsBetween tapsToAnswer transformLayout turn turnAt turnsFromAnswer Twist twistsOf VERSION WEST withMasks
armsOf(mask: number): number
How many sides a piece opens on.
blendOf(measure: Measure, reference: Reference): number
The blend of a board's five percentiles against reference, 0 to 1, before it is ranked among the blends.
canTurn(mask: number): boolean
Whether a piece can be turned into a new facing: ground, and a cross, look the same turned any way.
canTurnAt(game: Game, cell: number): boolean
Whether the piece on cell of a game can be turned: it is a piece that looks different turned, and it is not locked.
cellChar(mask: number, role?: "source" | "drain" | "plain"): string
A cell's character: its piece, marked as a source or a drain if it is one.
checkSuidoAnswer(board: string, answer: string): SuidoCheck
Whether an answer solves a board: the check a page makes to say "solved" and a server makes before it trusts a solve. O(cells): one walk of the water, no search.
The answer is a code like the board's own. Every cell of it must be the piece the board has there, turned (a piece is never changed, moved or taken away), and the sources and drains must be where the board put them. Then the water is run from the sources through the answer's pieces, and the board must be solved: a network, every piece wet; drains, every drain wet; and either way no wet piece opens on nothing; an inlet-outlet board also asks that the water runs in one path. Locked pieces must be as the board gives them, and the walls must be the board's walls.
It does not ask whether the board is one a site has made: a site that pays or ranks for a solve asks that first.
countSolutions(layout: Layout, limit?: number, budget?: number): number
How many answers there are, counted up to limit.
decodeLayout(code: string): Layout | null
The board a code stands for, or null when it is not one: a bad size, an unknown character, a source or drain on bare ground, or no source at all.
deduce(layout: Layout, solution: readonly number[]): Deduction
The deductions of a board, in rounds. Each round looks at every piece at once, as the board stood at the end of the last, and fixes every piece whose facing is now forced. A network does it by what each piece may still face (a piece must open back on a neighbour that must open towards it); a drains board does it by growing from the pumps and the drains. solution is an answer to the board, which says which pieces a drains board's water goes through.
type Deduction = { /** The pieces the water goes through in the answer. */ pieces: number; /** Pieces whose facing is forced at the first look, by the edge, bare ground, or a piece beside them that has to open or cannot. */ glance: number; /** Pieces forced by the end, when no look forces any more. */ settled: number; /** How many looks changed something: the longest chain of "this forces that". */ rounds: number; };
What a player can work out without guessing, as a person would: look at every piece, fix what is forced, and look again.
DIFFICULTY_SIDES: readonly number[]
The sizes (side of the board) there is a reference set for.
DIFFICULTY_WEIGHTS: Record<Kind, Record<MeasureName, number>>
The weights of the measures in the blend, for each kind.
difficultyOf(layout: Layout, solution: readonly number[]): number
How hard a board is, 1 to 100 among boards of its size, from the board as given and one of its answers.
EAST: 2
encodeLayout(layout: Layout): string
The code of a board.
exactDifficultyOf(layout: Layout, solution: readonly number[]): number
The same before it is rounded to a whole number, from 1 to 100: the order boards are put in.
exactScoreOf(measure: Measure, reference: Reference): number
The score of a measure against a reference set before it is rounded, from 1 to 100: what boards are put in order by, so that two boards of one whole score still have an order.
type Flow = { /** Whether the water has reached each cell. */ wet: boolean[]; /** The cell the water came from into each wet cell; -1 for a source and for a dry cell. */ from: number[]; /** The side each wet cell was entered on, the side facing `from`; -1 for a source and for a dry cell. */ entry: number[]; /** How many cells the water went through to get to each wet cell, 0 at a source; -1 for a dry cell. */ depth:…
Where the water is on a board as it is turned: the whole picture, from the pump outwards.
flowOf(layout: Layout, masks?: readonly number[]): Flow
The water on a board whose pieces face as masks say. It starts at every source and goes through every opening that meets an opening of the piece beside it; whatever it reaches is wet. Plain breadth-first search, one visit to each cell.
flowOfGame(game: Game): Flow
The water on a game.
type Game = { /** The board as it was first given. */ start: Layout; /** The sides each piece opens on now. */ masks: number[]; /** Quarter turns clockwise each piece has had, counting a turn the other way as minus one. */ quarters: number[]; /** Taps that turned a piece. */ turns: number; };
A game in play: the board as it was given, how every piece faces now, and how far each has been turned in all (kept as a count rather than a facing, so a drawing can turn a piece the way it was tapped, never the long way round).
gameCode(game: Game): string
The game as a code, every piece facing as it does now: what to keep to come back to it, and what to send to be checked.
gameFromProgress(code: string, progress: string): Game | null
The game a board's code and a kept gameProgress make, or null when the code is not a board or the progress is not one of that board's.
gameProgress(game: Game): string
A game half played, as a short string to keep: one digit for each piece (the quarter turns clockwise it has had from the way the board gave it, 0 to 3), a colon, and the number of taps made. gameFromProgress brings it back.
hintFor(game: Game, answer: readonly number[]): number | null
A piece to turn, for a player who asks for help: the first piece that does not face as answer says, nearest the pump first (the water's own order), or null when every piece does. In a drains board a spare piece is never one.
isGameSolved(game: Game): boolean
Whether the game is solved: the same test the check makes of an answer.
isLocked(layout: Pick<Layout, "locked">, cell: number): boolean
Whether a piece is locked on this board.
isSolved(layout: Layout, masks?: readonly number[]): boolean
Whether a board facing as masks say is solved.
isTwisted(layout: Pick<Layout, "kind" | "wrap" | "sources" | "locked" | "walls">): boolean
Whether a board has any twist.
type Kind = "network" | "drains" | "inlet-outlet";
What a board asks of the water.
type Layout = { width: number; height: number; kind: Kind; /** Whether the edges join: the east of the last column is the first, the south of the last row the top. */ wrap: boolean; /** The sides each piece opens on, as the board is given or as it is turned; 0 is blank ground. */ cells: number[]; /** The cells the water comes from, in order. */ sources: number[]; /** The cells the water must reach, in order. */ drai…
A board. network: every piece must end up wet, and no wet piece may open on nothing. drains: every drain must be reached, and no wet piece may open on nothing; a piece the water does not reach is a spare, and may face any way. inlet-outlet: one pump and one drain, each an end piece; the water must run from the one to the other through one unbranched path (every wet piece opens on two sides and no more), with nothing left open. Spares may face any way.
laySuido(options?: MakeOptions): Made
A board laid out and turned at random, with no promise about how many answers it has: the raw material makeSuido shapes. Its solution is one answer.
type Made = { /** The board as the player first sees it, every piece turned at random. */ code: string; /** The board solved: the same pieces facing as the answer has them. */ answer: string; layout: Layout; /** The sides the answer's pieces open on. */ solution: number[]; seed: number; /** How many boards were laid and thrown away before this one had exactly one answer. */ discarded: number; };
A new board: its code, the code of its one answer, and what it was made from.
type MadeScored = Made & { /** 1 to 100 among boards of its size: see `difficultyOf`. */ difficulty: number; /** How many boards were made to find it, when a difficulty was asked for. */ tried: number; };
A new board with how hard it is.
type MakeOptions = { /** The same seed and the same options make the same board, in every browser and every Node. */ seed?: number; /** The side of a square board; or `width` and `height` for one that is not. Default 7. */ size?: number; width?: number; height?: number; /** * `network` (every piece wet), `drains` (every drain reached, spare pieces allowed) or `inlet-outlet` * (the water runs in one path from the pum…
What a new board may be asked for. Everything has a default but the seed, and a seed has one too.
makeSuido(options?: MakeOptions): MadeScored
Makes a board with exactly one answer and says how hard it is. With a difficulty asked for it makes boards (each its own seed, the first the seed given) until one is within tolerance of it, or attempts have been made, and gives the nearest. The board's seed is the one that made it, so makeSuido({ ...options, seed: made.seed }) makes it again.
makeUnscored(options?: MakeOptions): Made
Makes a board that has exactly one answer. A random forest rarely has one the first time: where the solver finds a second answer, the cells the two answers disagree on are where to look, and a pipe beside one of them is moved (or a spare piece taken off) until it does. Where walls or locks are asked for, they are what is built first, and any not needed are added at the end. A board the solver cannot prove inside its budget is thrown away.
MAX_SIDE: 40
The largest side a board may have.
type Measure = { kind: Kind; wrap: boolean; /** The pieces the water goes through in the answer. */ pieces: number; /** 1 less the share of pieces plain at the first look. */ obscure: number; /** Looks that changed something. */ rounds: number; /** The share of the pieces still open when looking forces nothing more. */ unsettled: number; /** 0 for no guessing; otherwise positions that branched, then positions looked…
What is measured of one board.
MEASURE_NAMES: readonly MeasureName[]
The measures, in the order the reference lists them.
type MeasureName = "obscure" | "rounds" | "unsettled" | "guessing" | "spares";
The measures, by name.
measureSuido(layout: Layout, solution: readonly number[]): Measure
Every measure of one board, from the board as given and one of its answers.
neighboursOf(layout: Pick<Layout, "width" | "height" | "wrap"> & { walls?: readonly number[]; }): Int32Array
Which cell is next to each cell on each side: table[cell * 4 + side], or -1 where there is no cell (the edge of a board that does not wrap) or a wall.
newGame(code: string): Game | null
A game on a board, with every piece as given. Null when the code is not a board.
NORTH: 1
A side of a cell. They go round clockwise, so a quarter turn adds one.
opposite(side: number): number
The side a piece next door must open on to meet an opening on side side.
percentileIn(quantiles: readonly number[], value: number): number
Where value stands among sorted quantiles, 0 to 1: how far through them it is, by the share of the way between neighbours.
quantilesOf(values: readonly number[], points: number): number[]
Quantiles of a list of numbers, at points even steps from least to greatest, for a reference set.
quartersBetween(from: number, to: number): number | null
The fewest quarter turns, clockwise, that make from into to; null when they are not the same shape.
type Random = () => number;
A number in [0, 1), like Math.random, from a stream a seed fixes.
type Reference = Record<MeasureName, number[]> & { blend: number[] };
A reference set of boards, as quantiles: every measure at 21 even steps from its least to its greatest, and the blend of the five at 101.
referenceFor(layout: Pick<Layout, "width" | "height" | "kind" | "wrap">): Reference
The reference set a board is scored against: that of the board's side (the square root of its cells, to the nearest size there is a set for), kind and wrap. A board of a size no set was made for is scored among the nearest. A board's walls and locked pieces are not part of its set: they make it easier than the boards of its set, and its score says so.
referenceKey(side: number, kind: Kind, wrap: boolean): string
The key a reference set is kept under.
rotationsOf(mask: number): number[]
Every way a piece can face, each once and in order: one for a cross, two for a straight, four for the rest.
scoreOf(measure: Measure, reference: Reference): number
The score of a measure against a reference set: 1 (the plainest of its size) to 100.
seededRandom(seed: number): Random
A stream of numbers in [0, 1) fixed by a seed.
type Shape = "blank" | "end" | "straight" | "elbow" | "tee" | "cross";
What a piece is, by how many sides it opens on and where.
SHAPE_MASKS: Record<Shape, number>
A piece of each shape facing north, as the drawings and the tests name them.
shapeOf(mask: number): Shape
The shape of a piece, from the sides it opens on.
shuffled<T>(items: readonly T[], random: Random): T[]
A copy of the list in a random order (Fisher–Yates); the list given is left alone.
SIDE_STEPS: readonly [readonly [0, -1], readonly [1, 0], readonly [0, 1], readonly [-1, 0]]
The step across each side, as columns and rows.
SIDES: readonly [1, 2, 4, 8]
The four sides by number, 0 (north) to 3 (west): the bit of side i is 1 << i.
solve(layout: Layout, limit?: number, budget?: number): SolveResult
Counts the answers to a board, up to limit, stopping early when budget positions have been looked at. One answer is the whole point of a board: count === 1 && complete is the proof.
A network is solved as a puzzle of what each piece may face: every piece starts with its rotations, and a piece's opening on a side must be matched by its neighbour's opening back (and an absence by an absence) until nothing more can be removed; the search then picks the piece with fewest ways left and tries each. Pieces the water could never reach, in any way the rest could still face, end that branch at once. A drains board is solved the other way round, because a spare piece may face any way: it grows a network from the sources and the drains, settling what its openings force and trying what they do not, and counts each distinct network once. An inlet-outlet board is solved as a drains board in which a piece the water goes through opens on two sides at most. Locked pieces have the one way they are given, and walls are edges the neighbour table does not cross, so neither needs a rule of its own.
type SolveResult = { /** How many answers there are, counted up to the limit asked for. */ count: number; /** Each answer found, as the sides every piece opens on. In a drains board a piece the water does not reach stays as it was given. */ solutions: number[][]; /** The positions the search looked at, and how many of them had more than one way on to try. */ nodes: number; branches: number; /** The pieces fixed by d…
What the solver found.
SOUTH: 4
SUIDO_TWISTS: readonly Twist[]
Every twist, in the order the levels teach them.
type SuidoCheck = { ok: true } | { ok: false; reason: string };
What a check says: solved, or the first reason it is not.
symmetryKey(layout: Layout, solution: readonly number[]): string
A board's identity up to turning and mirroring it: the smallest of the codes of its eight turns and mirrors, with every piece the water does not go through (it may face any way) set to one facing. Two boards with the same key are the same puzzle. solution is the board with its pieces facing as an answer has them.
tapsBetween(from: number, to: number, both?: boolean): number | null
The taps it takes to face a piece the right way when a tap turns it one way only (both false) or either way (both true, the shorter of the two).
tapsToAnswer(game: Game, answer: readonly number[], both?: boolean): number
The fewest taps that would turn every piece to face as answer says, when a tap turns a piece either way (both, the default) or clockwise only.
transformLayout(layout: Layout, op: number): Layout
A board's cells, pumps, drains, locks and walls moved by one of the eight turns and mirrors: op 0 to 3 turn it a quarter at a time, 4 to 7 do so after a mirror.
turn(mask: number, quarters?: number): number
A piece turned quarters quarter turns clockwise; a negative number turns it the other way.
turnAt(game: Game, cell: number, by?: 1 | -1): Game
A tap: the piece on cell turned a quarter, clockwise (by 1) or the other way (by -1). Returns a new game. A cell that cannot be turned (bare ground, a cross, a locked piece), or does not exist, leaves the game as it was.
turnsFromAnswer(given: readonly number[], solution: readonly number[]): number
The turns a board needs, when taps turn a piece either way: how far it is from solved.
type Twist = "drains" | "pumps" | "locked" | "walls" | "wrap" | "inlet-outlet";
THE TWISTS: what a board can ask of a player beyond turning every piece until the water reaches all of them. Each is a thing the board itself says (its code carries it), a level declares it on its row, and a page shows it as a chip.
- drains: the water must reach every drain, not every piece; pieces it does not need are spares and may stay dry, facing any way. - pumps: more than one pump, each feeding its own pipes. - locked: some pieces cannot be turned. They are given facing the way the answer has them, and are the first things to build the rest from. - walls: water cannot cross some of the edges between cells, so a pipe opening on one runs out of it as it does at the edge of the board. - wrap: the edges of the board join, left to right and top to bottom. - inlet-outlet: one pump at the top left and one drain at the bottom right, and the water must run between them in one path with no branch; the rest of the pieces are decoys and stay dry.
A plain board has none: its single pump feeds a network and every piece must be wet.
twistsOf(layout: Pick<Layout, "kind" | "wrap" | "sources" | "locked" | "walls">): Twist[]
The twists a board has, in the order the levels teach them: none for a plain board.
VERSION: "1.3.0"
The package's version.
WEST: 8
withMasks(layout: Layout, masks: readonly number[]): Layout
The same board with its pieces facing as masks says, which is how a half-played board or an answer is kept.
@johnmorrisdotca/suido/drawArmState CellState cellStates DrawOptions drawPiece drawSuido drawSuidoThumb paintSuido stepFor SUIDO_STYLE
type ArmState = "in" | "out" | "leak" | "";
What the water does at one opening of a piece.
type CellState = { cell: number; /** Quarter turns clockwise from the piece as the board gave it, as the drawing turns it. */ quarters: number; wet: boolean; /** Cells the water went through to reach it, 0 for a pump; -1 for a dry cell. */ depth: number; /** What the water does at each of the piece's four sides as drawn (the sides it had as the board gave it, not as it faces now): "in" where it comes in, "out" where…
How one cell is to look.
cellStates(layout: Layout, masks?: readonly number[], quarters?: readonly number[], flow?: Flow): CellState[]
The state of every cell of a board whose pieces face as masks say.
type DrawOptions = { /** How every piece faces now; the board's own, if left out. */ masks?: readonly number[]; /** How far each piece has been turned in all, so a drawing can keep turning the way it was tapped; found from `masks` if left out. */ quarters?: readonly number[]; /** A description for screen readers. */ label?: string; /** Put `SUIDO_STYLE` inside the drawing, so it stands alone as an image. A page with…
What to draw with.
drawPiece(mask: number, options?: { wet?: boolean; label?: string; style?: boolean; }): string
One piece on its own, as SVG text: for a legend, an icon, or a page that shows how the pieces look. wet fills it with water.
drawSuido(layout: Layout, options?: DrawOptions): string
A board as SVG text. The pieces face as options.masks say, with the water in them as it runs from the pumps through every opening that meets another. The drawing is class="suido"; its colours and its flowing are SUIDO_STYLE.
drawSuidoThumb(layout: Layout, options?: { masks?: readonly number[]; label?: string; style?: boolean; water?: boolean; }): string
A board as a small picture, in a few dozen elements however big the board is: for a page that shows a whole block of levels at once. The pipes are one path, the water in them (where the pieces face as masks say and the water reaches) another, with the pumps, the drains, the padlocks and the walls on them. It carries no cells to tap and nothing that moves; it is class="suido" so it takes the same colours.
paintSuido(svg: Element, layout: Layout, masks: readonly number[], quarters: readonly number[]): Flow
PAINTING the water onto a board drawSuido drew, in place: nothing is redrawn, so the pipes turn and the water flows (and runs back) by the style's transitions. Call it after every tap, with how the pieces face now and how far each has been turned in all (Game.masks and Game.quarters). It sets data-wet, data-solved, data-w and the --k, --q and --sd-step custom properties and nothing else, and returns the water.
stepFor(deepest: number): number
The milliseconds the water takes through one cell, so that the deepest cell is reached in FILL_MS at most.
SUIDO_STYLE: "\n.suido {\n --sd-step: 80ms;\n --sd-line: #d9d1bf; --sd-ground: #fbf8f1; --sd-edge: #3b4148; --sd-pipe: #aeb7c0; --sd-water: #1b8fe3;\n --sd-source: #1b5fa6; --sd-bowl: #3b6a7e; --sd-leak: #e04a2f; --sd-focus: #b5452c; --sd-hint: #f6dc8a; --sd-solved: #e8f3ec;\n --sd-wall: #7a4f2c; --sd-lock: #8a6a2e;\n display: block; width: 100%; height: auto;\n user-select: none; -webkit-user-select: none; -webkit-…
THE STYLE a Suido board is drawn with: colours as custom properties, the water's flow as transitions, and the one rule that matters for a game played with fingers: nothing on the board can be selected, dragged or double-tapped.
The drawing (drawSuido) and the painting (paintSuido) only set data attributes and two custom properties, and this is what turns them into water: data-w on each arm of a pipe says whether the water comes in by it, goes out by it, or runs out of it (a leak); --k on a cell is how many cells the water went through to get there, and each cell's water starts a step after the one before, so it is seen to flow from the pump out along the pipes. It runs backwards, quickly, when a pipe is broken. With reduced motion asked for, it all happens at once.
Walls are bars across the edges they are on (--sd-wall) and a locked piece has a frame and a padlock (--sd-lock). Every colour is a custom property on .suido (--sd-ground, --sd-edge, --sd-pipe, --sd-water, --sd-source, --sd-bowl, --sd-leak, ...), so a page's own style needs only to set the ones it wants different.
@johnmorrisdotca/suido/playensureSuidoPlayStyle mountSuido SUIDO_PLAY_STYLE SUIDO_STRINGS SuidoEventDetail SuidoLanguage suidoLanguageOf SuidoMount SuidoMountOptions suidoSay SuidoTurning
ensureSuidoPlayStyle(host: Element): void
Put the style in the page once: in the document's head, or in the shadow root the host is in.
mountSuido(host: HTMLElement, options: SuidoMountOptions): SuidoMount | null
Draw a board into host and play it. Returns the handle that drives it, or null for a code that is no board.
SUIDO_PLAY_STYLE: "\n.suido {\n --sd-step: 80ms;\n --sd-line: #d9d1bf; --sd-ground: #fbf8f1; --sd-edge: #3b4148; --sd-pipe: #aeb7c0; --sd-water: #1b8fe3;\n --sd-source: #1b5fa6; --sd-bowl: #3b6a7e; --sd-leak: #e04a2f; --sd-focus: #b5452c; --sd-hint: #f6dc8a; --sd-solved: #e8f3ec;\n --sd-wall: #7a4f2c; --sd-lock: #8a6a2e;\n display: block; width: 100%; height: auto;\n user-select: none; -webkit-user-select: none; -we…
THE STYLE a playable Suido board wears (mountSuido, <suido-board>): the drawing's own (SUIDO_STYLE) and the board's box, its chips, its lines of words and its buttons. Colours are custom properties on .suido-play (--sdp-ink, --sdp-muted, --sdp-rule, --sdp-surface, --sdp-accent, --sdp-good) so a page sets only what it wants different.
Nothing moves when something is chosen: the board is one box in the board's own shape, the lines of words keep the room their longest wording takes, and the buttons are one size.
SUIDO_STRINGS: Record<SuidoLanguage, Record<string, string>>
type SuidoEventDetail = { /** The game as a code, every piece facing as it does now: what `checkSuidoAnswer` takes, with the board's own code. */ code: string; /** The game as a short string to keep a game half played (`gameFromProgress` and the `progress` option bring it back). */ progress: string; /** Taps that turned a piece. */ turns: number; /** Hints asked for. */ hints: number; solved: boolean; /** The piece …
What a mounted board tells of itself in every event.
type SuidoLanguage = "en" | "ja";
THE WORDS A SUIDO BOARD SAYS, in English and Japanese: what a screen reader hears of each cell, the buttons and the lines of words under a playable board, and what each twist means. Plain data, so a page can read them, replace a few or add a language of its own beside these two.
{name} in a line is a value filled in; a line foo that has a fooOne beside it is said as fooOne when its {n} is 1.
suidoLanguageOf(tag: string | null | undefined): SuidoLanguage
The language a piece of text is in: Japanese for anything starting ja, English for everything else.
type SuidoMount = { readonly host: HTMLElement; /** The game as it stands. */ game: () => Game; /** The water as it runs now. */ flow: () => Flow; /** The game half played, as a short string to keep. */ progress: () => string; /** Play another board (or the same one again, fresh). `progress` carries on a kept game and `shown` opens on the answer. */ load: (board: { code: string; answer?: string; progress?: string; s…
type SuidoMountOptions = { /** The board, as its code (`makeSuido(...).code`, or a level's `row[0]`). */ code: string; /** The board's one answer, as a code (`levelAnswer(row)`, `makeSuido(...).answer`). With it Hint is offered if `hints` is on, and the meter says par. Ignored if it is not an answer to the board. */ answer?: string; /** A game half played, as `gameProgress` or an event's `progress` wrote it. */ prog…
suidoSay(language: SuidoLanguage, key: string, values?: Record<string, string | number>): string
A line in a language, with its values filled in; the line itself if there is none by that name.
type SuidoTurning = "clockwise" | "anticlockwise";
The way a tap turns a piece.
@johnmorrisdotca/suido/elementSuidoBoard: typeof SuidoBoard
@johnmorrisdotca/suido/element/define@johnmorrisdotca/suido/levelsblockOf blockRange blocksIn dailySuidoLevel declaredTwists firstUnsolvedSuidoLevel isSuidoDay isSuidoLevel levelAnswer levelBoard LevelRow levelSolution loadEverySuidoLevel loadSuidoLevels nextSuidoLevel openSuidoLevels sizeOf SUIDO_BLOCK SUIDO_DAILY_STRIDE SUIDO_LEVEL_COUNTS SUIDO_SIZES suidoBand SuidoBand suidoDay SuidoDay suidoLevelOf suidoLevelsOf suidoMarks suidoRole SuidoSize turnsOf twistRole TwistRole
blockOf(level: number): number
The block a level is in, from 1.
blockRange(block: number, count: number): { first: number; last: number; }
A block's first and last level, the last no further than the size has.
blocksIn(count: number): number
How many blocks a size of count levels has.
dailySuidoLevel(size: string, date: string | Date): number | null
The level of the day at a size: a whole number from 1 to that size's count of levels, or null for a size there are no levels of. It ignores which blocks a player has opened: today's level is open to everybody.
declaredTwists(row: LevelRow): Twist[]
The twists a row declares, in the order the levels teach them. A word that is no twist is dropped; levels.test.ts holds each row's list to its board.
firstUnsolvedSuidoLevel(size: string, solved: ReadonlySet<number>): number | null
The lowest level not yet solved, or null when every level of the size is. It is always open: a block opens only once the block before is all solved, so the first gap is in the open blocks.
isSuidoDay(text: string): boolean
Whether a text is a real date written YYYY-MM-DD: 2026-02-30 is not.
isSuidoLevel(size: string, level: number): boolean
Whether a number is a level this size has.
levelAnswer(row: LevelRow): string | null
A row's answer as a code, the board's own code with every piece facing as the answer has it: what checkSuidoAnswer is given. Null for a row that is not a board and its turns.
levelBoard(row: LevelRow): Layout | null
The board a row stands for, or null for a row whose code is not a board.
type LevelRow = readonly [board: string, turns: string, twists: string];
One level: its board as a code (code.ts), its answer as one digit a cell, and its twists.
levelSolution(row: LevelRow): number[] | null
The pieces of a row's answer, each facing as the answer has it; null for a row that is not a board and its turns.
loadEverySuidoLevel(): Promise<void>
Every size's levels, loaded.
loadSuidoLevels(size: string): Promise<readonly LevelRow[]>
A size's levels, loaded once and kept.
nextSuidoLevel(size: string, solved: ReadonlySet<number>): number
The level to open on: the first open one not yet solved, or the last open one when every open level is solved.
openSuidoLevels(size: string, solved: ReadonlySet<number>): number
The levels that are open, given the ones solved: the first block of sixteen always, and each block after it once every level of the block before is solved.
sizeOf(size: string): { width: number; height: number; } | null
The width and height of a size.
SUIDO_BLOCK: 16
SUIDO'S BLOCKS: its levels come sixteen at a time, as Tsunagi's do. A block opens once every level of the block before it is solved, a page shows one block at a time, and within a block the levels rise; the 15th and 16th of a block are where its twist takes: the 15th teaches it and the 16th tests it.
Its own module, with nothing imported, so the level-making script on a desk reads the same number a page does.
SUIDO_DAILY_STRIDE: 97
Each day moves this many levels along a size's ladder, round to the start when it runs out. It is prime, and no size's count of levels is a multiple of it.
SUIDO_LEVEL_COUNTS: Readonly<Record<string, number>>
How many levels each size has, read without loading the size: whole blocks of sixteen (levelBlocks.ts).
SUIDO_SIZES: readonly `${number}x${number}`[]
The square sizes, 5×5 to 14×14, then three pipe shapes: long boards, 5×7, 6×10 and 8×14.
suidoBand(size: string, level: number): SuidoBand
Which third of a size a level sits in: its first third easy, its middle medium, its last hard.
type SuidoBand = "easy" | "medium" | "hard";
The third of a size a level sits in.
suidoDay(date: string | Date): SuidoDay
The day a moment falls on, in UTC, or the same day if it is already written as one. Throws on a date that is not one.
type SuidoDay = string;
A calendar date, YYYY-MM-DD.
suidoLevelOf(size: string, board: string): number | null
The level a board is, at a loaded size, or null for a board no level has.
suidoLevelsOf(size: string): readonly LevelRow[]
A size already loaded, or a refusal: nothing answers for a list it does not have.
suidoMarks(size: string, level: number): number | null
A level's measured difficulty, 1 (easiest) to 5, or null for a level the marks do not have: read without loading the size's boards.
suidoRole(size: string, level: number): TwistRole | null
A level's part in its block's lesson, from the data the level script wrote (marks.data.ts), without its size's boards; null for none.
type SuidoSize = `${number}x${number}`;
A size of board, as its code writes it: its width, an x, its height.
turnsOf(layout: Layout, solution: readonly number[]): string | null
The answer to a board as one digit a cell: how many quarter turns clockwise each piece needs, the fewest. Null when solution is not the board's pieces turned.
twistRole(rows: readonly LevelRow[], level: number): TwistRole | null
A level's part in its block's lesson, or null for a level that has none (1 to 14 of a block, or a 15th or 16th with no twist).
type TwistRole = { role: "teaches" | "tests"; twists: Twist[]; newOnes: Twist[] };
Where a level sits in its block's lesson: its 15th teaches the twist, its 16th tests it. newOnes are the twists no earlier level of the size has.
@johnmorrisdotca/suido/levels-5x5SUIDO_5X5: readonly (readonly [string, string, string])[]
SUIDO AT 5×5: 256 levels in blocks of 16, each no easier than the one before by the measured difficulty (difficulty.ts), each block's 15th and 16th its twist from the second block on.
WRITTEN BY node scripts/suido-levels.ts, NEVER BY HAND. Each line is one level: its board as a code (code.ts), its answer as a digit for each cell (the quarter turns clockwise from the way the board gives the piece to the way the answer has it), and the twists it declares. Every level is proved to have exactly one answer by levels.test.ts, no two are the same board under a turn or a mirror, and the order is held to the measure.
@johnmorrisdotca/suido/levels-6x6SUIDO_6X6: readonly (readonly [string, string, string])[]
SUIDO AT 6×6: 256 levels in blocks of 16, each no easier than the one before by the measured difficulty (difficulty.ts), each block's 15th and 16th its twist from the second block on.
WRITTEN BY node scripts/suido-levels.ts, NEVER BY HAND. Each line is one level: its board as a code (code.ts), its answer as a digit for each cell (the quarter turns clockwise from the way the board gives the piece to the way the answer has it), and the twists it declares. Every level is proved to have exactly one answer by levels.test.ts, no two are the same board under a turn or a mirror, and the order is held to the measure.
@johnmorrisdotca/suido/levels-7x7SUIDO_7X7: readonly (readonly [string, string, string])[]
SUIDO AT 7×7: 256 levels in blocks of 16, each no easier than the one before by the measured difficulty (difficulty.ts), each block's 15th and 16th its twist from the second block on.
WRITTEN BY node scripts/suido-levels.ts, NEVER BY HAND. Each line is one level: its board as a code (code.ts), its answer as a digit for each cell (the quarter turns clockwise from the way the board gives the piece to the way the answer has it), and the twists it declares. Every level is proved to have exactly one answer by levels.test.ts, no two are the same board under a turn or a mirror, and the order is held to the measure.
@johnmorrisdotca/suido/levels-8x8SUIDO_8X8: readonly (readonly [string, string, string])[]
SUIDO AT 8×8: 256 levels in blocks of 16, each no easier than the one before by the measured difficulty (difficulty.ts), each block's 15th and 16th its twist from the second block on.
WRITTEN BY node scripts/suido-levels.ts, NEVER BY HAND. Each line is one level: its board as a code (code.ts), its answer as a digit for each cell (the quarter turns clockwise from the way the board gives the piece to the way the answer has it), and the twists it declares. Every level is proved to have exactly one answer by levels.test.ts, no two are the same board under a turn or a mirror, and the order is held to the measure.
@johnmorrisdotca/suido/levels-9x9SUIDO_9X9: readonly (readonly [string, string, string])[]
SUIDO AT 9×9: 256 levels in blocks of 16, each no easier than the one before by the measured difficulty (difficulty.ts), each block's 15th and 16th its twist from the second block on.
WRITTEN BY node scripts/suido-levels.ts, NEVER BY HAND. Each line is one level: its board as a code (code.ts), its answer as a digit for each cell (the quarter turns clockwise from the way the board gives the piece to the way the answer has it), and the twists it declares. Every level is proved to have exactly one answer by levels.test.ts, no two are the same board under a turn or a mirror, and the order is held to the measure.
@johnmorrisdotca/suido/levels-10x10SUIDO_10X10: readonly (readonly [string, string, string])[]
SUIDO AT 10×10: 256 levels in blocks of 16, each no easier than the one before by the measured difficulty (difficulty.ts), each block's 15th and 16th its twist from the second block on.
WRITTEN BY node scripts/suido-levels.ts, NEVER BY HAND. Each line is one level: its board as a code (code.ts), its answer as a digit for each cell (the quarter turns clockwise from the way the board gives the piece to the way the answer has it), and the twists it declares. Every level is proved to have exactly one answer by levels.test.ts, no two are the same board under a turn or a mirror, and the order is held to the measure.
@johnmorrisdotca/suido/levels-11x11SUIDO_11X11: readonly (readonly [string, string, string])[]
SUIDO AT 11×11: 256 levels in blocks of 16, each no easier than the one before by the measured difficulty (difficulty.ts), each block's 15th and 16th its twist from the second block on.
WRITTEN BY node scripts/suido-levels.ts, NEVER BY HAND. Each line is one level: its board as a code (code.ts), its answer as a digit for each cell (the quarter turns clockwise from the way the board gives the piece to the way the answer has it), and the twists it declares. Every level is proved to have exactly one answer by levels.test.ts, no two are the same board under a turn or a mirror, and the order is held to the measure.
@johnmorrisdotca/suido/levels-12x12SUIDO_12X12: readonly (readonly [string, string, string])[]
SUIDO AT 12×12: 256 levels in blocks of 16, each no easier than the one before by the measured difficulty (difficulty.ts), each block's 15th and 16th its twist from the second block on.
WRITTEN BY node scripts/suido-levels.ts, NEVER BY HAND. Each line is one level: its board as a code (code.ts), its answer as a digit for each cell (the quarter turns clockwise from the way the board gives the piece to the way the answer has it), and the twists it declares. Every level is proved to have exactly one answer by levels.test.ts, no two are the same board under a turn or a mirror, and the order is held to the measure.
@johnmorrisdotca/suido/levels-13x13SUIDO_13X13: readonly (readonly [string, string, string])[]
SUIDO AT 13×13: 256 levels in blocks of 16, each no easier than the one before by the measured difficulty (difficulty.ts), each block's 15th and 16th its twist from the second block on.
WRITTEN BY node scripts/suido-levels.ts, NEVER BY HAND. Each line is one level: its board as a code (code.ts), its answer as a digit for each cell (the quarter turns clockwise from the way the board gives the piece to the way the answer has it), and the twists it declares. Every level is proved to have exactly one answer by levels.test.ts, no two are the same board under a turn or a mirror, and the order is held to the measure.
@johnmorrisdotca/suido/levels-14x14SUIDO_14X14: readonly (readonly [string, string, string])[]
SUIDO AT 14×14: 256 levels in blocks of 16, each no easier than the one before by the measured difficulty (difficulty.ts), each block's 15th and 16th its twist from the second block on.
WRITTEN BY node scripts/suido-levels.ts, NEVER BY HAND. Each line is one level: its board as a code (code.ts), its answer as a digit for each cell (the quarter turns clockwise from the way the board gives the piece to the way the answer has it), and the twists it declares. Every level is proved to have exactly one answer by levels.test.ts, no two are the same board under a turn or a mirror, and the order is held to the measure.
@johnmorrisdotca/suido/levels-5x7SUIDO_5X7: readonly (readonly [string, string, string])[]
SUIDO AT 5×7: 256 levels in blocks of 16, each no easier than the one before by the measured difficulty (difficulty.ts), each block's 15th and 16th its twist from the second block on.
WRITTEN BY node scripts/suido-levels.ts, NEVER BY HAND. Each line is one level: its board as a code (code.ts), its answer as a digit for each cell (the quarter turns clockwise from the way the board gives the piece to the way the answer has it), and the twists it declares. Every level is proved to have exactly one answer by levels.test.ts, no two are the same board under a turn or a mirror, and the order is held to the measure.
@johnmorrisdotca/suido/levels-6x10SUIDO_6X10: readonly (readonly [string, string, string])[]
SUIDO AT 6×10: 256 levels in blocks of 16, each no easier than the one before by the measured difficulty (difficulty.ts), each block's 15th and 16th its twist from the second block on.
WRITTEN BY node scripts/suido-levels.ts, NEVER BY HAND. Each line is one level: its board as a code (code.ts), its answer as a digit for each cell (the quarter turns clockwise from the way the board gives the piece to the way the answer has it), and the twists it declares. Every level is proved to have exactly one answer by levels.test.ts, no two are the same board under a turn or a mirror, and the order is held to the measure.
@johnmorrisdotca/suido/levels-8x14SUIDO_8X14: readonly (readonly [string, string, string])[]
SUIDO AT 8×14: 256 levels in blocks of 16, each no easier than the one before by the measured difficulty (difficulty.ts), each block's 15th and 16th its twist from the second block on.
WRITTEN BY node scripts/suido-levels.ts, NEVER BY HAND. Each line is one level: its board as a code (code.ts), its answer as a digit for each cell (the quarter turns clockwise from the way the board gives the piece to the way the answer has it), and the twists it declares. Every level is proved to have exactly one answer by levels.test.ts, no two are the same board under a turn or a mirror, and the order is held to the measure.
@johnmorrisdotca/suido/marksSUIDO_MARKS: Readonly<Record<string, string>>
SUIDO_ROLES: Readonly<Record<string, Readonly<Record<number, TwistRole>>>>
この日本語は、まだ日本語を母語とする方の確認を受けていません。訂正を歓迎します。