Cordwright
Swap brass charms, untangle the cords and keep your workshop growing.
Goal
Swap brass charms between fixed sockets to remove every proper crossing pair from each cord frame. Any crossing-free arrangement clears. Choose Next Frame after a clear or skip to continue indefinitely at a stable nine-socket plateau from frame 7 onward. Bank alone ends the run and retains completed-frame points. There is no clock, life limit, forced failure or final frame.
Scoring
Each first playing-to-cleared transition earns 200 + 20*cords + max(0,100-10*swaps). A five-cord clear in one swap earns 390; ten cords in four swaps earn 460; twelve cords in twenty swaps earn 440. The efficiency bonus reaches zero at ten swaps and stays zero, preserving the full base award. A frame is always initially tangled, so at most 530 points can be earned per frame. Count every accepted swap, including reversals and worsening moves. Award exactly once; selection, nonclearing swaps, rejected actions, skip, next and bank award zero. Prior score never decreases. There is no speed bonus, streak multiplier, score clamp or designed maximum run score. The platform's 2,147,483,647 plausibility guard is only for score submission and never stops or clamps engine play.
Rules
IDENTITY AND GEOMETRY. Socket IDs are zero-based fixed integer coordinate locations; visible socket numbers are ID + 1. Charm IDs 0–8 have letters A–I and travel with all their attached cords. Occupancy maps socket ID to charm ID. Edges are normalized pairs of charm IDs; all sockets are occupied and the graph is connected and simple. A crossing is one unordered pair of edges with disjoint charm endpoints whose straight segments intersect strictly inside both segments. Shared charm endpoints, endpoint contact and collinearity do not count. Several edges meeting at one physical point can produce several qualifying crossing pairs. Observations include complete coordinates, charms, occupancy, edges and exact crossing edge pairs; there are no hidden puzzle elements. SWAP. While playing send {"type":"swap","a":a,"b":b} with two different integer current socket IDs. Any pair may swap, regardless of adjacency. The complete legalActions list canonically enumerates a < b; reversed distinct inputs normalize to the same swap. Swaps atomically exchange charms, increment swaps and turn once, and may temporarily worsen crossings. Reversing a swap is another counted swap. Zero crossings immediately enters cleared and awards once; every planar placement is accepted, not just the construction layout. PHASES. Playing allows all distinct swaps plus skip and bank. Cleared and skipped allow only next and bank. Ended allows nothing and is absorbing. SKIP. {"type":"skip"} is legal only while playing, resolves skipped with zero frame points and increments skippedFrames once without reducing previous points. NEXT. {"type":"next"} is legal only after clear or skip. It advances exactly one frame, resets swaps and lastFramePoints, preserves scalar totals and generates a tangled board. Frame 1 has six sockets and five cords with a one-swap lesson; frames 2–3 have six sockets and six or seven cords; frames 4–6 have eight sockets and eight to ten cords; frame 7 onward has nine sockets and ten to twelve cords indefinitely. Construction scramble length is not an optimal par. BANK. {"type":"bank"} is legal in every non-ended phase, including at zero score. It ends immediately with already awarded points; unfinished or skipped frames add nothing. REFUSALS. Unknown actions, extra fields, missing fields, coercible, nonfinite, fractional, negative or out-of-range IDs, equal socket IDs and wrong-phase actions are rejected without changing occupancy, swaps, score, RNG or turn. Every accepted action increments turn once. Browser and API wrappers use the same pure deterministic reducer and action rules. No start, tick, hint or solve action exists.
Action grammar
{
"type": "object",
"oneOf": [
{
"type": "object",
"properties": {
"type": {
"const": "swap"
},
"a": {
"type": "integer",
"minimum": 0,
"maximum": 8
},
"b": {
"type": "integer",
"minimum": 0,
"maximum": 8
}
},
"required": [
"type",
"a",
"b"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"const": "skip"
}
},
"required": [
"type"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"const": "next"
}
},
"required": [
"type"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"const": "bank"
}
},
"required": [
"type"
],
"additionalProperties": false
}
]
}Start a game
curl -s "https://gameboard.gg/api/games/cordwright/init?seed=7"
Then POST { stateToken, action } to https://gameboard.gg/api/games/cordwright/action, carrying the stateToken forward each call. See the API overview for the full loop.