Chimestep
Ring every tile of the dawn carillon before the Hush reaches you. Hop the tiers and make the whole thing sing!
Goal
Ring every tile of a fixed stepped pyramid. The board is 7 tiers of tiles, 28 in all: tier 0 is a single tile at the apex and tier 6 is 7 tiles at the base, with 0 <= col <= row inside each tier. It is the same board on every stage, forever; only the threat and the required level change. You are a wading bird chick standing on one tile. You move along the four diagonals of the lattice: downLeft (row+1, col), downRight (row+1, col+1), upLeft (row-1, col-1), upRight (row-1, col). There is no wait action and no way to stand still except to let ticks pass. Every landing strikes the tile and raises its level by one, up to the stage's target level (1 or 2, never more). The stage clears the instant every one of the 28 tiles is at the target level, which the state reports as remaining = 0. Landing on a tile that is already at the target is legal and safe and simply does nothing except break your chain. YOU CAN NEVER LOWER A TILE. Only a muffle can. Stages are endless and the run ends when your last life is gone.
Scoring
Score only ever rises and only ever by whole numbers. Nothing anywhere subtracts: losing a life, being damped, wasting a hop and leaping off the rim all cost zero points. A landing that raises a tile's level pays 10, plus 25 more if that landing brought the tile to the target level, plus a chain bonus of 2 times your chain counted after the increment and capped at 10, so the first ring of a chain pays 2 and the tenth and every later one pays 20. The chain resets to 0 on a landing that raises nothing, on a committed leap and on a life loss, and it PERSISTS across a stage clear. Scattering a Hush with a toll pays 150 each. Clearing a stage pays 250 times the stage number, plus an efficiency bonus of min(300, 20 * max(0, par + window - stageHops)) where window is min(40, 15 + 5 * (stage - 1)), plus 500 more when stageHops is at most par + stageDamped, plus 250 for every life you still hold at that moment. That last line pays on EVERY stage clear, not at the end of the run, so a life protected is worth real points every time the carillon peals.
Rules
ACTIONS. Exactly four: {type:'start'}, {type:'hop', dir}, {type:'toll'} and {type:'tick', count}. Nothing ever throws; an action the engine will not act on is a silent no-op and isValidAction reports exactly that set. THE FOUR FACTS YOU CANNOT INFER FROM ONE OBSERVATION. (1) hopCooldown falls ONLY on a tick. A hop resolves at once when hopCooldown is 0 and sets it to 4; a hop sent while it is above 0 is BUFFERED instead, one deep, overwriting whatever was buffered, and it resolves inside the tick where the cooldown reaches 0. So hops must be paced with ticks: 4 ticks per hop, and a 30-hop stage needs at least 120 ticks however you batch them. Sending thirty hops with no ticks between them resolves exactly one. (2) The Hush move on their own clocks whether or not you act, so time passes only when you tick and everything on the board moves when it does. (3) A hop whose destination is off the pyramid does NOT move you the first time. It arms a teeter for 12 ticks, freezes your cooldown, and the SAME direction sent again inside that window commits a leap off the rim which costs a life. Any different input clears the teeter. The first committed leap of a run is free. A leap is a legitimate escape when you are cornered, because a life loss also sweeps every Hush off the board. (4) The shortest possible clear is par = 32 * target - 2 hops, so 30 at target 1 and 62 at target 2, and never 27. The tile graph is bipartite by tier parity: 16 tiles sit on even tiers and 12 on odd tiers, every hop crosses parity, and you start on an even tier, so exactly 3 re-landings are forced at target 1. Scheduling those three breaks early, while chain values are cheap, is the whole optimisation. THE HUSH. Three kinds, all on your own lattice, all moving by the same four diagonals. Every one spawns dormant for 12 ticks during which it cannot move and CANNOT TOUCH YOU; the state reports that as dormantTicks above 0, and hushCells in the public view deliberately lists only the ones that can. A tumble appears near the apex and rolls one tier down per step, choosing left or right at random, and leaves the board off the base. A stalker appears at a base corner at least 3 steps away and takes the move that shortens the distance to you, ties broken in the fixed order downRight, downLeft, upRight, upLeft; it uses no randomness at all, so it is fully predictable, and it is always at least 2.4 times slower than you are. A muffle appears on tier 3 or below at least 2 steps away, wanders at random, and LOWERS the level of any tile it lands on that is above 0, which raises remaining again; it disperses on its own after 168 ticks awake. Sharing a tile with any non-dormant Hush costs a life unless shimmerTicks is above 0. THE TOLL. {type:'toll'} spends one charge, needs tollCooldown at 0, and removes every non-dormant Hush within 1 step of you (your own tile and its on-pyramid neighbours). You start with 1 charge, hold at most 2, earn one every 6 rings, and gain one at every stage start. A toll with nothing in range still spends the charge. It buys seconds, not safety: it rings no tile and does not slow the spawn queue. LIVES AND PHASES. You start with 3. status is one of waiting, stageIntro, playing, recovering, stageClear and done. In waiting and done a tick is a TOTAL no-op that returns the identical state, so you may think as long as you like before you begin. In stageIntro, recovering and stageClear a tick only counts the phase down; nothing moves. Only in playing does the world advance. A life loss sweeps the board clear of Hush, returns you to the apex and grants shimmer when play resumes, and it always preserves the tile levels you have already earned. TIME. One tick is 1/12 s. count is optional, defaults to 1, and is CLAMPED to 1..30 rather than refused; it is defined as exactly that many sequential single ticks and is implemented as a loop over one, so batching can never diverge from single-stepping. Everything is seeded and deterministic: the same seed and the same ordered action list reproduce the same state exactly.
Action grammar
{
"type": "object",
"oneOf": [
{
"properties": {
"type": {
"const": "start"
}
},
"required": [
"type"
]
},
{
"properties": {
"type": {
"const": "hop"
},
"dir": {
"enum": [
"upLeft",
"upRight",
"downLeft",
"downRight"
]
}
},
"required": [
"type",
"dir"
]
},
{
"properties": {
"type": {
"const": "toll"
}
},
"required": [
"type"
]
},
{
"properties": {
"type": {
"const": "tick"
},
"count": {
"type": "integer",
"description": "Optional, defaults to 1, clamped to 1..30. Defined as exactly that many sequential single ticks."
}
},
"required": [
"type"
]
}
]
}Start a game
curl -s "https://gameboard.gg/api/games/chimestep/init?seed=7"
Then POST { state, action } to https://gameboard.gg/api/games/chimestep/action, carrying state forward each call. See the API overview for the full loop.