Public: anyone can read this; the crew can change it.
forked from trevato/cs · proposes
procedurally generated maps #147
Check · Review · Land · Live done — Landed and live in production.
`/` answers in 8 ms with the map field in the first paint, `bun test` is green (647 tests), and the branch is pushed.
shipped production is serving it deploy ae07c2d
Sign in to join this conversation.
new above
offline
/answers in 8 ms with the map field in the first paint,bun testis green (647 tests), and the branch is pushed.---
src/client/generate.tsturns a number into a map: rooms, corridors, two bombsites, two spawns and cover, carved into the letterssrc/client/cells.tsreads — so a generated map is one more value ofLeveland nothing in the simulation, the bots or the renderer learns anything to play it. It is fair by construction: every cell is stamped twice, once at (col, row) and once half a circle away withtbecomingcandAbecomingB, and the sites are an odd number of cells on both sides so the plant point is the middle of a cell rather than a seam that rounds the wrong way on one side. Over 600 seeds the walk from CT spawn to A and from T spawn to B are the same length to the unit, both ways round. It is playable by construction: rooms hang off a spanning tree of corridors through the middle room that both halves share,regionrubs out what the tree missed, a crate that would cut the map in two is taken back off, andflawsreads the finished level — spawns, sites, a path from each spawn to each site, no floor that cannot be walked to — before it is handed over. 1,000 seeds, none needed a second attempt; a map costs 2.1 ms.Three things moved to make room for it.
src/client/cells.tsis the alphabet both maps are written in andlevelOfis the reading of it, somap.tsis now de_forge's areas and crates and nothing else — both golden digests are unmoved to the byte.regionjoins the engine's grid besidefindPath: every cell reachable from one you name, by the same eight steps with the same refusal to cut a corner.Renderer.replace(name, mesh)uploads one mesh again under a name the renderer already holds and gives the old one back, buffers included, because a match on another map needs the geometry changed and nothing else rebuilt.What to look at in the preview: the Map field on the menu — pick generated and the match id becomes the seed, so every match is a layout nobody has played; leave it on de_forge and not one byte of geometry is swapped.
src/client/generate.test.tsis where the claims are checked, including a pinned ten-second round of the real game with the real bots ongen_5, andpage(grid)prints a map as text if you want to read one.What I chose not to do: #96's half of this — the choice is not remembered between visits, the map is not posted with the result and the leaderboard says nothing about it, and there is no server-side list of known map names. That is server and menu plumbing and it belongs to the issue that waits on this one. I also left the sites deliberately bare: crates go on floor only, never on a bombsite, because a crate inside the site moves the centroid the bomb is planted at, and cover on a site is a decision to make on purpose rather than a side effect. The app bundle grew 4,604 raw / 2,035 gzipped and no longer fits 75,400/34,900, so its ceiling is 82,000/38,000 — today's 77,966 / 36,059 plus about five per cent, with the reasoning written into
src/games.tsbeside every other ceiling move.🤖 Generated with Claude Code
Closes #138