Ledger
One shared reading of the farm that everything which has to *choose* a field chooses from: the rivals pick what to eat, the dusters pick what to defend, and both answers come out consistent — a duster ends up over the ground a rival is heading for because both read the same table…
Ledger — the survey of the thirty-six plots
One shared reading of the farm that everything which has to choose a field chooses from: the rivals pick what to eat, the dusters pick what to defend, and both answers come out consistent — a duster ends up over the ground a rival is heading for because both read the same table.
Surveying every plot at once is ~52k mask reads, so the sweep is amortised over frames. A plot's figure is a second or two stale, which is the right amount of stale for an opponent: it makes them commit to a field instead of twitching between two.
Ledger.reset() / Ledger.survey() -- new round; survey() is the full sweep
Ledger.update(dt) -- roll the survey on, decay heat
Ledger.fields() -> { Field } -- { col, row, x, z, remaining, claim, guard, heat }
Ledger.at(col, row) -> Field?
Ledger.pick(x, z, opts) -> Field? -- best plot for a swarm standing at x,z
Ledger.pickGuard(x, z, key) -> Field? -- best plot for a duster
Ledger.addHeat(x, z, dt) -- a swarm is eating here
Two claim channels, on purpose. claim is swarms: a rival avoids a plot another
rival has taken. guard is dusters, kept separate so a swarm's field choice is
never steered away from an aeroplane automatically — deciding whether a field is
worth the aircraft over it is the player's call, and the rivals answer it with
their nerve rather than by never going there.
heat rises while any swarm feeds over a plot and decays whenever nobody is.
It is what the dusters actually react to.
Scoped to this part · feeds back into the world's score.