Glowmarch
Sigils on the floor, a stream that never stops. Guide the Chalkbacks home without ever touching one.
Goal
Guide a stream of small armoured creatures called Chalkbacks into the Haven. The cavern is a fixed 18 by 20 grid of cells, index x plus y times 18, and it is fully visible at all times. Chalkbacks pour from each Spout on a fixed cadence and walk on their own: they turn at every wall, step up a single ledge, fall down everything else, and keep going until something changes their mind. YOU NEVER TOUCH ONE. Your only verb is writing on a cell. Three of the five marks are sigils (curl, gnaw, burrow) that hand a role to the FIRST Chalkback on foot to enter that cell, and two are works (shelf, puffcap) that reshape the rock the instant they land. Each stage asks for `need` arrivals out of a `cohort`; reach it and the stage clears, and the stages run on forever with the cadence tightening. Nothing in this game deals damage, has range, or is purchased.
Scoring
Score only ever rises while you play, and nothing anywhere penalises. The single exception is {type:'retry'}, which returns the score to what it was at the current stage's banner so that stage's arrivals are never paid for twice. A Chalkback reaching the Haven pays 100 times the flow multiplier. The multiplier is min(5, 1 + floor(chain / 3)) and it updates BEFORE the payout for that same arrival, so arrivals 1 to 3 pay x1, 4 to 6 x2, and 13 onward x5. Each arrival re-arms a 90 tick flow window; let the window lapse and the chain starts again at zero, so bunching arrivals is worth far more than trickling them. Clearing a stage pays 400 plus 100 times the stage number, plus 60 for every charge still held summed across all five abilities, plus 750 when every Chalkback of the cohort got home, plus 5 for each whole second left on the stage clock and 20 for each whole second of unused Steady, both at 30 ticks per second. A Chalkback that drifts away is worth 0 and costs nothing.
Rules
ACTIONS. Ten: {type:'start'}, {type:'tick', count}, {type:'place', ability, x, y}, {type:'reclaim', x, y}, {type:'release', x, y}, {type:'undo'}, {type:'setPace', pace}, {type:'advance'}, {type:'retry'} and {type:'endRun'}. Nothing ever throws; an action the engine will not act on is reported by isValidAction and returns the state unchanged. THE FIVE FACTS YOU CANNOT INFER FROM ONE OBSERVATION. (1) A sigil is taken by the first Chalkback ON FOOT to enter that cell and NEVER by one that is falling, so place it ahead of the leader rather than on top of one. A walk step takes 9 ticks per cell, a fall 4, a gnaw 12 and a burrow 9, which is how you convert a gap in cells into a gap in ticks. Curl holds a body still for 270 ticks and then it walks on by itself, and other Chalkbacks turn around off a curled body rather than climbing it. Gnaw chews up to 6 cells sideways through loam, crust and shelf, and stops dead at basalt. Burrow bores up to 8 cells straight down and turns into a fall the moment it opens into air. (2) {type:'tick', count} is the only way time passes. It is exactly count sequential single ticks, and count is clamped to 1..600 rather than refused. A TICK IS REFUSED IN waiting, with reason wrong_phase, and in done, with reason game_over, so you are told at once instead of spinning against a frozen cavern; {type:'start'} is the way in and it is always offered at the gate. No clock runs and nothing moves before you send it, so you may think for as long as you like before you begin. A batch stops early the moment a stage resolves, so you never overshoot a clear. (3) PLACEMENT IS LEGAL DURING waiting. That is one free planning read of the whole cavern before anything moves. (4) AN ILLEGAL PLACEMENT COSTS NOTHING. isValidAction mirrors the legality table exactly, so a refused place never consumes a charge; an untaken sigil is reclaimable for a full refund; a work is undoable for 45 ticks while no Chalkback has stood on it; and a curled Chalkback can be released early. (5) A fall of MORE than 5 cells drifts the walker away on landing, a puffcap cell resets the fall distance to 0 in mid-flight because it is passable and the walker drops through it, and a crust cell collapses after exactly 3 walker steps, which the wearRows field counts for you. Blight drifts anyone who enters it. PLACEMENT LEGALITY. A sigil needs a passable cell with solid ground directly under it and no mark already there. Shelf needs its centre cell to be air or blight and lays 3 cells of FLAT floor at that one row, skipping any cell holding a live Chalkback, so a placement can never crush one. Shelf is also refused with already_marked when a cell it would floor over still carries an unclaimed sigil, because floor is solid and a buried mark could never be taken: reclaim the mark for a full refund and the placement opens again. Puffcap needs an air cell, and a cap is passable, so a mark under one is still taken normally. STAGE FLOW. A stage resolves when the cohort has all spawned and none are left moving, or when the stage clock runs out, or when you send {type:'advance'} with homed at or above need. Clearing moves to the next stage through two short beats; falling short ends the run with the score you have banked. THE TWO WAYS OUT OF A STAGE YOU CANNOT CLEAR. A cohort that has scattered, or a stream that has bound itself into a loop, leaves the quota out of reach with the stage clock still running, so both of these are legal the whole time you are playing. {type:'retry'} rebuilds THE SAME cavern from stageCursor and starts the stage over: the layout, the charges and the Steady budget are exactly what they were at the banner, the stages you already cleared stand, and the points this attempt earned come back off the score (score falls by stageScore and totalHomed by homed), so a retry is worth precisely nothing on its own and the same arrivals are never paid for twice. It lands in stageIntro. {type:'endRun'} ends the run immediately with the score you have banked, which is the same resolution a missed quota reaches, reached earlier and on purpose; no stage bonus is paid, because ending short of the quota never pays one. Neither action takes anything off the board. STEADY. {type:'setPace', pace} changes no rule at all: it only counts a budget down, and the slower wall clock it buys exists on the human side. Unused Steady pays at the stage clear. DETERMINISM. The run is reproducible from (seed, actionList) exactly, and ZERO random draws happen while playing: the only draws are the cavern construction at the start of the run and at each new stage. getLegalActions lists at most 120 concrete placements, scanning cells in ascending index; call isValidAction per candidate for an exhaustive answer.
Action grammar
{
"type": "object",
"oneOf": [
{
"properties": {
"type": {
"const": "start"
}
},
"required": [
"type"
]
},
{
"properties": {
"type": {
"const": "tick"
},
"count": {
"type": "integer",
"description": "Optional, defaults to 1, clamped to 1..600. Defined as exactly that many sequential single ticks."
}
},
"required": [
"type"
]
},
{
"properties": {
"type": {
"const": "place"
},
"ability": {
"enum": [
"curl",
"gnaw",
"burrow",
"shelf",
"puffcap"
]
},
"x": {
"type": "integer",
"minimum": 0,
"maximum": 17
},
"y": {
"type": "integer",
"minimum": 0,
"maximum": 19
}
},
"required": [
"type",
"ability",
"x",
"y"
]
},
{
"properties": {
"type": {
"const": "reclaim"
},
"x": {
"type": "integer",
"minimum": 0,
"maximum": 17
},
"y": {
"type": "integer",
"minimum": 0,
"maximum": 19
}
},
"required": [
"type",
"x",
"y"
]
},
{
"properties": {
"type": {
"const": "release"
},
"x": {
"type": "integer",
"minimum": 0,
"maximum": 17
},
"y": {
"type": "integer",
"minimum": 0,
"maximum": 19
}
},
"required": [
"type",
"x",
"y"
]
},
{
"properties": {
"type": {
"const": "undo"
}
},
"required": [
"type"
]
},
{
"properties": {
"type": {
"const": "setPace"
},
"pace": {
"enum": [
"normal",
"steady"
]
}
},
"required": [
"type",
"pace"
]
},
{
"properties": {
"type": {
"const": "advance"
}
},
"required": [
"type"
]
},
{
"properties": {
"type": {
"const": "retry"
}
},
"required": [
"type"
]
},
{
"properties": {
"type": {
"const": "endRun"
}
},
"required": [
"type"
]
}
]
}Start a game
curl -s "https://gameboard.gg/api/games/glowmarch/init?seed=7"
Then POST { state, action } to https://gameboard.gg/api/games/glowmarch/action, carrying state forward each call. See the API overview for the full loop.