Skip to content

bc20: Battlecode 2020 "Soup" as the second year module - #1

Merged
daveey merged 5 commits into
mainfrom
bc20-year-module
Sep 4, 2026
Merged

bc20: Battlecode 2020 "Soup" as the second year module#1
daveey merged 5 commits into
mainfrom
bc20-year-module

Conversation

@daveey

@daveey daveey commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Adds the bc20 year module — MIT Battlecode 2020 "Soup" — beside bc26,
behind the year-module boundary the 2026 build cut for exactly this.
Implements docs/plans/2026-09-04-battlecode-2020-soup-design.md.

DO NOT MERGE YET — the coordinator decides merge timing.

What lands

  • src/battlecode/years/bc20/ — the sim: the numbered resolution rules 1–9
    mirroring GameWorld.runRound, the flood (a committed JDK-generated
    float32 water table
    , because Math.exp/Math.sin are HotSpot intrinsics),
    soup and refining, the seven build types, dig/dump elevation, drone
    carry/drop-in-water, net guns, pollution (a refinery's local +500 lasts
    exactly one round), the 64-int blockchain with its cost model and the
    static-Random re-seed-per-spawn quirk, the ported cows, the six-rung
    tiebreak ladder, and a 1500-round cap applied through the engine's own
    round >= rounds - 1.
  • Two chassis: bowl-of-chowder (behaviour port, AGPL-3.0 provenance,
    parameterised by the ten knobs, with real defensive play) and
    examplefuncsplayer (statement-for-statement, and it may not gain
    behaviour
    — it is one side of the differential oracle).
  • The ten-knob doctrine sheet with no chassis key (D1), 18 converted
    .map20 maps, and the 2020 sprite atlas cut from the official client.
  • Manifest: variant bc20 (num_agents: 2 inside game_config), the
    year-neutral results_schema.games.items.required with each year's stats as
    optional siblings, a fourth docs page, two more baselines, four more
    policies. bc26's variant, its player entries and the certification fixture
    are byte-identical.
  • Viewer: an appended bc20 game block with all-new #bc20-* ids and a
    data-year CSS gate. chrome_common.js, broadcast_core.js,
    config.nims and both static_replay*.js are untouched.
  • GameVersionGV05, ReplayCompatibleGameVersions ["GV04", "GV05"].

Evidence

  • parity-oracle-bc20: a 67 559-line vector file emitted from the pinned
    2020 engine sources under JDK 8 and from the Nim port, diffed byte for byte
    — the water table, both pollution coefficients over all 65 536 values,
    Math.round(float), the IDGenerator streams, java.util.Random, the
    overflowing cow seed and Transaction.compareTo. Blocking.
  • docker-smoke runs two episodes (bc26 cert fixture + a 300-round bc20
    scripted game) and wasm-viewer executes the bundle against both
    replays.
  • Thirteen new tests/test_bc20_*.nim shards, including the D1 no-chassis
    assertion, the D2 survival gate and a ten-knob teeth gate. No existing test
    was weakened or deleted.

docs/RULES-BC20.md §Divergences lists every deliberate difference from the
2020 engine, including the one the oracle cannot cover: the full round-loop
tier needs :engine:jar, and net.sf.jsi:jsi:1.1.0-SNAPSHOT no longer exists
on any repository the upstream build names.

Adds `src/battlecode/years/bc20/` — world, flood, pollution, blockchain,
cows, maps, knobs, rules and the two chassis — plus the committed data the
sim reads: 18 converted `.map20` maps, the JDK-generated float32
water-level table, and the 2020 sprite atlas cut from the official client.

The year-neutral machinery (`match`, `results`, `replay`, `render`,
`broadcast`, `decide`, `server`, the wasm entry) now goes through
`years/dispatch.nim`, the one place a year is named; `sheet.nim` is thinned
to the envelope and each year's knob table moves to `years/<year>/knobs.nim`,
with the tolerant-parsing primitives extracted UNCHANGED into
`sheet_common.nim`. bc26 semantics are untouched: every existing test passes
in debug and release.
Adds the `bc20` manifest variant (num_agents 2 inside its own game_config),
the four-year-neutral `results_schema.games.items.required` with each year's
statistics as optional siblings, the fourth docs page, the two bc20 baseline
player entries and the four bc20 policies. bc26's variant, its player entries
and the certification fixture are byte-identical.

Bumps GameVersion to GV04 with ReplayCompatibleGameVersions [GV03, GV04]:
nothing a GV03 recording carries changed meaning, so every hosted bc26 replay
keeps rendering.

Adds tests/test_bc20_{flood,dirt,drone,burial,blockchain,pollution,cows,
scoring,sheet,maps,baselines,knobs,perf}.nim — including the D1 no-chassis
assertion, the D2 survival gate and the ten-knob teeth gate.
The viewer: `client/replay_broadcast.html` gains an APPENDED bc20 game block
with all-new `#bc20-*` ids, a `data-year` CSS gate and CSS for all ten beat
kinds; the D3 dismissible doctrine overlay (close button, Esc, re-open chip)
sits above `var(--band)`, never in it. `chrome_common.js`,
`broadcast_core.js`, `config.nims` and both `static_replay*.js` are
byte-for-byte untouched, so no loader is spliced. The renderer fixture gains a
bc20 ROW: three widths x two years, checked with --strict-text-bounds.

The oracle: `tools/oracle/Bc20Oracle.java` and `tools/parity_trace_bc20.nim`
emit the same 67 559-line vector file from the pinned 2020 engine sources and
from the Nim port -- the water table, both pollution coefficients over all
65 536 values, Math.round(float), the IDGenerator streams, java.util.Random,
the OVERFLOWING cow seed and Transaction's comparator. They diff clean.
`tools/oracle/examplefuncsplayer20/` carries the one-hunk determinism patch.

CI: a `parity-oracle-bc20` job (JDK 8, two BLOCKING tiers plus a reported
engine-from-source attempt), `docker-smoke` runs TWO episodes, `wasm-viewer`
executes the bundle against BOTH replays, and the `test` job re-generates and
byte-diffs every bc20 generated artefact against the pinned 2020 checkout.
GameVersion becomes GV05 (main spent GV04 on the D1/D2 chassis change) with
ReplayCompatibleGameVersions [GV04, GV05]: the bc20 addition changes no bc26
semantics, so a GV04 recording still re-derives, while GV03 stays out because
the D2 chassis change means it does not.

Conflict resolution took MAIN's side for every bc26 semantic: the post-D1 knob
table (no `chassis` key, `parseChassis` for playback) moves verbatim into
`years/bc26/knobs.nim`, `baselines.chassisFor` keeps setting the filler
path's chassis directly, and `replay.parseSeat` keeps restoring it. bc20's
own `parseChassis` is renamed `parseChassisKind` so the two never collide.
`#bc20-doctrines` adopts main's stricter D3 discipline: it auto-closes on the
first advancing frame and after six seconds, its body is capped and scrolls,
and CI's obscured-board gate now runs against BOTH years' replays.
`docs/RULES-BC20.md` is the 2020 rule set, its ten knobs and a fourteen-item
Divergences list — including the two the design note could not have known:
the chassis walls before `wall_hq_round` when the map's own flood schedule
demands it (`maptestsmall`'s HQ ring floods at round 256), and the wall bar is
evaluated at the last round the game can reach rather than at `round + 400`.

`docs/PARITY.md` gains the bc20 oracle: what the 67 559 vector lines pin, and
why the round-loop tier is blocked — `net.sf.jsi:jsi:1.1.0-SNAPSHOT` was
published only to jcenter (shut down 2022) and the Sonatype OSS SNAPSHOTS repo
(expired), and `world/ObjectInfo.java` imports it directly, so the unmodified
upstream build cannot produce `:engine:jar` in 2026. The job attempts it
anyway and prints the exact failure to the summary.

`NOTICE` names battlecode20 (GPL-3.0, compatible with this repo's AGPL-3.0
under AGPLv3 section 13) file by file, StoneT2000/Battlecode2020 (AGPL-3.0) as
the behaviour `bowl-of-chowder` distils, and IvanGeffner/battlecode2020 as
cited-never-used.

`tests/test_bc20_replay.nim` adds record -> re-derive for every bc20 end
reason including the wall-clock stop, a strict UTF-8 parse of the written
bytes, and the assertion that the blockchain is re-derived from events +
config + seed with nothing stored.
@daveey
daveey merged commit 551c542 into main Sep 4, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant