feat(games): fourteen more for the arcade — eight to twenty-two - #367
Merged
Conversation
`/games stagedive` (also `dive`, `runner`, `stage`). You are running the barricade: hop the monitor wedges, clear the amp stacks, duck the crowdsurfers, take the picks. One mistake is the whole run. A side-scroller in a terminal is really a scrolling list — the runner never moves along the x axis at all, everything else slides left past a fixed column. That is why speed is measured in columns per tick, and why the gap between hazards is multiplied by it: a jump lasts a fixed number of ticks, so a fair gap has to get longer as the stage gets faster. Without that the stage eventually outruns the jump and the game stops being losable-by-mistake and starts being unfair. Three things to read and two ways to answer. Wedges and stacks are jumped, and the stack is two rows tall so it takes the height of the jump rather than the start of it. A crowdsurfer sits at head height: crouch and it goes over you, because a crouched runner is one row and a standing one is two. `↓` in mid-air is a slam instead, which is how you save a jump you took too early. Every hazard's hitbox is its own art, so a hazard cannot hit wider than it is drawn — the oldest bug in the genre. The tests play it: a jump at six columns clears a wedge and a jump one column late still wrecks on a stack, and a player with reflexes runs 25 seeded stages to the end while standing still and holding jump both die on every one of them. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Five more for the cabinet, on the same frame, decoder and driver as the rest. Space Invaders is the one with the joke the original hardware told by accident: cadence() divides by the number left alive, so forty of them crawl and the last one sprints. Bunkers take two hits a cell from either side — including yours, which is the whole reason stepping out from under your own cover is a skill. Breakout's paddle is a steering wheel rather than a wall: where the ball lands on it decides the angle it leaves at, which is what lets you dig a channel up the side. Pong's machine waits until the ball crosses the halfway line and then moves too slowly to reach a corner from the middle, so a flat return it always gets and a sharp one it never does. Tank searches the yard rather than facing you and driving: breadth-first over 546 cells, every decision. "Turn towards the enemy" grinds into the same block for ever, and the first version of this duel finished 0–0 after twenty thousand ticks with neither tank ever having found the other. Spy Hunter's road is generated a row at a time from the row before it, with the bend pulled back towards the middle in proportion to how far out it already is. A plain random walk parks the road against one edge and leaves it there, which reads as a bug rather than a road. Three bugs worth naming, all found by playing them without a terminal: - The invader ranks were two rows apart, which made the fleet nine rows tall on a board with eleven above the bunkers. It "landed" after two drops and no wave was survivable by anybody. One row per rank, and an aiming player now always dies to the bombs instead — which is the test. - Shots that move faster than their target is tall skipped straight through it. Both the cannon and the car now travel in sub-steps and check what they pass. - The tank yard's size was declared next to the map it described, and disagreed with it. It is derived from the map now. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Centipede's body is not a linked list, it is a bag of segments that each obey the same rule: walk sideways, and when something is in the way drop a row and turn round. Modelled that way a shot to the middle needs no surgery — you delete one segment and the ones behind it carry on, which is exactly what splitting looks like. Every piece you shoot leaves a mushroom where it fell, so the field thickens as you play and the next wave is harder for free. The spider is in there because without it the bottom of the board is safe: the centipede only reaches your row on the sweeps it happens to end on, and a player who never moves at all survived three thousand ticks. It comes in from the side, bounces diagonally through your strip eating mushrooms, and is worth more than anything else on the board. Standing still now loses on every seed, which is the test. Frogger is the inversion: on the road, being on something is death; on the river, being on nothing is. The log carries you, including off the end of the world, which is the lesson every player learns twice. Landing on the bank between the homes is a loss and so is a home you have already filled. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Dig Dug has no pathfinding, and that is the design: a monster walks the tunnel it is in and turns towards you at a junction, so the shape you dig is the shape of the fight. Dig one straight line and they queue up behind you. Once in a while one gives up on the tunnels and comes straight through the ground, because without that a player who digs a single deep hole is untouchable. The harpoon only travels down open tunnel, three pumps burst a monster, and walking away drops it — so the pump is a commitment, not a button. Kong's girders are flat. The originals slope, and a slope is the one thing a terminal row cannot honestly draw; faking it with half-blocks makes a board that looks like the arcade and plays like a bug report. What the slope *does* is kept: each girder has a direction, they alternate, and the barrel chute sits at the far end of each one, so barrels cross a whole girder before they drop. Two rounds of that layout were unplayable before this one, both found by playing it without a terminal: - Barrels flipped direction when they landed, which sent them back the way they came and straight off the board. Nothing ever reached the lower girders and a player who never moved could not be hit at all. - With one ladder per girder, the only way up was the chute the barrels come down — a coin toss you cannot jump out of. Each girder has a second ladder now, and a climbing player reaches level 21 before the pace catches them. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Pitfall's vine is what stops it being another jumping game. A jump is short and you commit to it the instant you press it; a swing is long and can only be started where a vine hangs. The spawner never puts down a pit without a vine over it, because a pit is five columns wide and a jump covers about five — a pit with no vine is a pit nobody gets past, and that is a test rather than a promise. Tuning it was the usual business of playing it without a terminal: the first swing was sixteen ticks, which carried you over all of a pit except its last column, and the first jump was seven, which cleared a log and landed you on its back half. Long enough now that a player who jumps and swings at the right moments is only ever beaten by the clock — which is the game Pitfall actually is. Choplifter keeps its world in world columns and only turns them into screen columns in render(). The map is three screens wide with the pad at the far left end, so "get them home" is a journey rather than a step, and the camera follows you. Four seats in the back, and a hit costs everybody in them. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Excitebike is two mechanics and a side-scroller to hang them on. Turbo is free until it isn't — heat climbs while it is held and the engine seizes at the top of the gauge, so a fast race is one that cools off in the right places. And a jump is only as good as its landing: the nose drops on its own all the way down, and you pitch against it. That last part was inert in the first version. The ramp set your pitch and nothing changed it, so whatever you left the ramp with you landed on, and the landing — the second half of the game — could be ignored entirely. A rider who holds turbo and never touches the pitch now spills two hundred times over eight runs, where one who rides it properly spills none. That difference is the test. OutRun is the only board in the cabinet that fakes a third dimension, and it does it the way the eighties did: the road is not an object, it is a rule for drawing a row. roadHalf() and centreAt() are the entire renderer, and the same two functions decide what you have hit — so what is drawn and what is solid cannot drift apart. The bend is squared against distance, which is why it opens up towards the horizon and closes to nothing under your bumper, and why a corner throws you at the outside of itself. The clock is the opponent. The first checkpoint handed back 420 ticks for 260 of road, which meant a competent driver's clock only ever grew; it is 220 for 320 now, which is about fifty ticks of slack at full speed and none at all if you spin. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
ThreatCrush Security Scan95 finding(s) HIGH/CRITICAL: 5 | MEDIUM: 39 | LOW: 51
…and 45 more. Full results in the Security tab. Snippets are redacted; ThreatCrush never prints matched credential material. |
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #366, which merged while the rest of this was still being built: main got
asteroidsandblackjack, and these are the other fourteen. Same frame, same key decoder, same driver.invaderscentipedebreakoutpongtankdigdugfroggerkongpitfallchoplifterspyhunteroutrunexcitebikestagediveEvery game is tested for winnable and losable
A bot that plays properly has to get somewhere; a bot that doesn't has to die. That pair is what caught the real bugs:
Not built
Donkey Kong's sloped girders and Pole Position's perspective road are the two things a terminal row cannot draw honestly. Kong is here with flat girders — the slope's job is kept, since each girder has a direction and the chute sits at its far end, so you meet barrels head-on rather than following them. Pole Position's road is here as OutRun, which is the same renderer with a clock worth playing against; a second copy with a lap counter would have been the same game twice.
189 tests in
test/games.test.mjs; full suite 1546 pass, 0 fail. Played in a real pty as well as in the harness.🤖 Generated with Claude Code