The pack
ropeUntangle
function ropeUntangle(): Pack<{ ropeUntangle: RopeUntangleApi }>
The rope-untangle pack: game.ropeUntangle, the rules, the generator and the physical ropes.
Helpers
createUntangle
function createUntangle(level: UntangleLevel): UntangleGame
Make a game of a level. Throws, listing every problem, on a level validateUntangleLevel refuses.
createUntangleFeel
function createUntangleFeel(game: UntangleGame, options: UntangleFeelOptions = {}): UntangleFeel
Make the physical ropes of a game. They follow the game's state: moves, undo, redo and restarts.
generateUntangle
function generateUntangle(options: UntangleGenerateOptions = {}): UntangleLevel
Make a level. Throws when the layout cannot hold the ropes, or the scramble cannot reach the crossings asked for.
searchUntangle
function searchUntangle(level: UntangleLevel, from?: Readonly<UntangleState>, options: { maxStates?: number } = {}): UntangleMove[] | null
Search for moves that win a level from a state (default its start): best first, by crossings and unmet targets
plus half the moves so far. Returns the moves, an empty list when the state is already won, or null when no win is
found within maxStates states (default 20,000).
segmentsCross
function segmentsCross(ax: number, ay: number, bx: number, by: number, cx: number, cy: number, dx: number, dy: number): { x: number; y: number } | null
Whether two segments cross: properly, or overlapping along a line. Touching at an end does not count.
validateUntangleLevel
function validateUntangleLevel(level: UntangleLevel): string[]
Check a level and say what is wrong with it, as plain sentences; empty when it can be played.
Types
RopeUntangleApi
interface RopeUntangleApi
What the rope-untangle pack adds to a game: game.ropeUntangle.
create: typeof createUntangle— Make a game of a level.generate: typeof generateUntangle— Make a level by scrambling a solved board.validate: typeof validateUntangleLevel— Check a level; empty when it can be played.search: typeof searchUntangle— Search for a win from a state.feel: typeof createUntangleFeel— Physical ropes that follow a game's plugs, for feel.
UntangleCrossing
interface UntangleCrossing
Where two ropes cross, and which lies over.
over: string— The rope on top.under: string— The rope beneath.x: number— Where, across.y: number— Where, down.
UntangleEnd
type UntangleEnd = { socket: string } | { anchor: { x: number; y: number } }
A rope's end: a plug in a socket, which the player moves, or a fixed anchor (a hanging rope's top).
UntangleEvent
type UntangleEvent = | { kind: 'move'; move: UntangleMove; crossings: number } | { kind: 'clear'; rope: string } | { kind: 'won'; moves: number; stars: number } | { kind: 'lost' }
What happened, for the presenter.
UntangleFeel
interface UntangleFeel
The physical ropes of an untangle game.
readonly world: RopeWorld— The rope world, for drawing or colliders.hold(rope: string, end: 0 | 1, point: { x: number; y: number }): void— A plug in the hand: from now on that end followspoint(call again as the hand moves).release(): void— Let go: the plug goes back to wherever the rules have it (its new socket, after a move).readonly held: { rope: string; end: 0 | 1 } | null— The plug in the hand, or null.step(dt: number): void— Advance the ropes bydtseconds.view(): { id: string; colour?: string; points: number[]; layer: number; fade: number; ends: [{ x: number; y: number }, { x: number; y: number }] }[]— Each rope to draw, bottom first: its polyline[x0, y0, z0, x1, …](one run), its layer, and how far it has faded out (0 on the board, rising to 1 as a cleared rope leaves).
UntangleFeelOptions
interface UntangleFeelOptions
How the ropes feel.
gravity?: number— Gravity, units per second squared, down the board. Default 0: a board seen from above, where ropes lie flat. Give about 900 for hanging ropes seen from the side.slack?: number— Rope length beyond the distance between its ends, as a fraction. Default 0.08 hanging. From above the default is -0.03: a stretchy cord a little shorter than the gap, so its own tension keeps it straight (with no gravity, a slack rope keeps whatever waves it is given).stretch?: number— Stretch compliance (see physics-rope): 0 inextensible. Default 3e-4 from above, a stretchy cord; 0 hanging.radius?: number— The ropes' radius. Default 6.damping?: number— How quickly ropes stop moving, per second. Default 6 from above, 1 hanging.rope?: Omit<RopeWorldOptions, 'gravity' | 'damping' | 'flat'>— More rope-world options (step, iterations).
UntangleGame
interface UntangleGame
A game of one level.
readonly level: Readonly<UntangleLevel>— The level, as played (a copy).readonly rules: Readonly<Required<Omit<UntangleRules, 'moves'>>> & { readonly moves: number | null }— The rules in force: the level's, with the defaults filled in.readonly state: Readonly<UntangleState>— The state, live.crossings(): UntangleCrossing[]— Every crossing now.refuse(move: UntangleMove): string | null— Why a move cannot be made, or null when it can.move(move: UntangleMove): { ok: true } | { ok: false; reason: string }— Make a move. Returns whether it was made, and why not.free(): string[]— The sockets no plug is in.moves(): UntangleMove[]— Every move that can be made now.undo(): boolean— Undo the last move. False when there is none.redo(): boolean— Redo an undone move. False when there is none.readonly canUndo: boolean— Whether there is a move to undo.readonly canRedo: boolean— Whether there is a move to redo.restart(): void— Start the level again.hint(maxStates?: number): UntangleMove | null— A move towards the win, or null when none is found withinmaxStatesstates (default 20,000).stars(): number— Stars for the moves made: 3 at or under par, 2 within half again, else 1.drain(): UntangleEvent[]— What happened since the last drain, oldest first.view(): UntangleView— Everything to draw.snapshot(): UntangleSave— The game as plain JSON: the moves, replayed on restore.restore(save: UntangleSave): void— Resume a snapshot of this level. Throws on another level's, and the game is left as it was.
UntangleGenerateOptions
interface UntangleGenerateOptions
How to make a level.
seed?: number— The seed. The same options and seed give the same level. Default 0.id?: string— An id for the level. Defaultuntangle-<seed>.width?: number— The board's width. Default 600.height?: number— The board's height. Default 800.layout?: UntangleLayout— Where the sockets go. Default a 4 × 5 grid.ropes?: number— How many ropes. Default 5.crossings?: number— The fewest crossings to scramble to. Default the rope count.scramble?: number— The fewest scrambling moves. Default the rope count.rules?: UntangleRules— The rule variations. Thetargetsandbothwins colour each rope's home sockets.colours?: ReadonlyArray<string>— The rope colours, in order (repeated when there are more ropes).minimum?: number— The fewest moves the level must need: the best solution the search finds must be at least this long. Default 0. This, with the crossings, is the difficulty; the rope count is not.search?: number— How many states the search may try for a shorter solution (or any, when undoing the scramble is blocked). Default 4,000.
UntangleLayout
type UntangleLayout = /** A grid of holes, a peg board: `cols` across, `rows` down. */ | { kind: 'grid'; cols: number; rows: number } /** A ring of holes. */ | { kind: 'ring'; count: number } /** * Hanging ropes: one anchor per rope along the top, and `slots` sockets in each of `rows` rows below (more slots * than ropes leaves room to move). */ | { kind: 'hanging'; slots: number; rows?: number } /** Your own sockets. */ | { kind: 'sockets'; sockets: ReadonlyArray<{ x: number; y: number }> }
Where the sockets go.
UntangleLevel
interface UntangleLevel
A level.
id?: string— Its id, which saves carry.name?: string— A name to show.width: number— The board's width, for presenters.height: number— The board's height, for presenters.sockets: UntangleSocket[]— The sockets.ropes: UntangleRope[]— The ropes, where they start.order?: string[]— Which ropes lie over which at the start, bottom first. Default the order ofropes.rules?: UntangleRules— The rule variations.par?: number— Moves for three stars. Default none: every win is three stars.solution?: UntangleMove[]— A known solution, from the generator.
UntangleMove
interface UntangleMove
A move: take one end of a rope (0 or 1) to a free socket.
rope: string— The rope.end: 0 | 1— Which end.to: string— The free socket it goes to.
UntangleRope
interface UntangleRope
A rope.
id: string— Its id, unique on the board.colour?: string— Its colour, for drawing and for thetargetswin.ends: [UntangleEnd, UntangleEnd]— Its two ends. At least one must be a plug.
UntangleRules
interface UntangleRules
The rule variations.
win?: 'untangled' | 'targets' | 'both'— When the level is won:'untangled'(the default) when no rope crosses another,'targets'when every plug sits in a socket of its rope's colour,'both'when both hold.lock?: boolean— A rope with another lying over it is pinned: its plugs cannot move. Default false.clear?: boolean— A rope that crosses nothing after a move leaves the board, freeing its sockets. Default false.moves?: number— The most moves allowed; the level is lost when they run out. Default no limit.
UntangleSave
interface UntangleSave
A saved game.
format: 'phaser-ae-rope-untangle'— Always'phaser-ae-rope-untangle'.version: 1— The save format's version, 1.level: string— The level's id ('' for a level without one).history: ReturnType<History<UntangleState, UntangleMove>['snapshot']>— The moves, as the kernel's history saves them.
UntangleSocket
interface UntangleSocket
A socket a plug can sit in.
id: string— Its id, unique on the board.x: number— Where it is, across.y: number— Where it is, down.colour?: string— The colour a rope must reach here, for thetargetswin. Default none.
UntangleState
interface UntangleState
The game's state: plain JSON.
ends: Record<string, [UntangleEnd, UntangleEnd]>— Each rope's ends now.order: string[]— Which rope lies over which, bottom first.cleared: string[]— The ropes that have left the board (theclearrule).moves: number— Moves made.phase: 'playing' | 'won' | 'lost'—'playing', then'won', or'lost'when the moves run out.
UntangleView
interface UntangleView
Everything a presenter draws.
sockets: { id: string; x: number; y: number; colour?: string; rope: string | null; end: 0 | 1 | null }[]— Each socket, its colour, and which rope's plug is in it.ropes: { id: string; colour?: string; a: { x: number; y: number }; b: { x: number; y: number }; layer: number; plugs: [boolean, boolean]; tangled: boolean; locked: boolean; onTarget: [boolean, boolean]; }[]— Each rope still on the board, bottom first: its ends, its layer, whether it crosses anything, whether it is pinned (thelockrule), and whether each end is on its colour.crossings: UntangleCrossing[]— Every crossing.cleared: string[]— The ropes that have left the board.


