robo_rumble (faber_tweann v2.4.0)
View SourceRobo Rumble: a battle between N entrants, on one machine, publishable.
THIS EXISTS SO A TANK CAN FIGHT ON A STRANGER'S MACHINE. A leaf node accepts entrants, runs ONE battle, and publishes what happened. Nothing recomputes it and no second machine has to agree, because only one ever runs the fight.
BUILD, NOT CLAIM. Tests and a commit, no pre-registration and no gate.
THE ENGINE WAS ALREADY N-TANK AND NOBODY HAD NOTICED. robo_sim:new/1 takes a list of any length, robo_sim:finished/1 is "one or fewer still alive", which is last-tank-standing, and robo_match's loop already acts on every live tank. What was duel-shaped was the SCORING: robo_match:report/2 reads exactly two tanks named a and b, and its act_one/4 assumes every entrant is a robo_gauntlet kind. So this module is a new head on an existing loop, not a new engine.
TWO KINDS OF ENTRANT, because a battle royale full of strangers is not the first thing anyone will run. A house bot makes a one-tank test meaningful and gives a visiting genome something to be measured against.
{genome, robo_genome:genome()} driven by robo_pilot {script, robo_gauntlet:kind()} driven by robo_gauntlet
EVERY FOREIGN GENOME IS VALIDATED BEFORE THE BATTLE STARTS, never during. A genome that fails validation makes the whole battle refuse rather than one entrant silently misbehave, because robo_net:fit/2 pads a wrong-width input layer in silence and robo_pilot falls back to a null intent on a short output vector. A mismatched genome therefore does not crash: it fights badly and produces a result that looks real.
PLACEMENT IS A RULE OF THE GAME AND IT IS HERE. Entrants are spaced evenly on a circle and face the centre, so no entrant gets a better seat than another and adding one more competitor does not quietly change the geometry for everybody. The circle is derived from the arena rather than chosen, and it is INTEGER, so a placement is reproducible from the entrant count alone.
WHAT A RESULT CARRIES, and it is chosen so a battle can be replayed from it rather than streamed. The genome ids, the placement, the engine fingerprint and the outcome. A spectator does not receive frames; they receive this and regenerate the fight locally.
Summary
Types
-type entrant() :: {term(), {genome, robo_genome:genome()} | {script, atom()}}.