robo_sim (faber_tweann v2.4.0)

View Source

Robo Rumble: a deterministic 2D tank-arena engine (pure, process-free).

The instrument for the Robo Rumble front (faber-ecosystem PLAN_ROBO_RUMBLE.md, phase 0). Successor substrate to flatland_sim, chosen because it differs from the exhausted pursuit-evasion grid on three axes: PARTIAL OBSERVABILITY (a radar that sweeps, so you see only what you scan), an ENERGY ECONOMY WITH A REAL DECISION (firing costs energy, hitting returns more than it cost), and a high-dimensional action space (body, gun and radar steer independently).

DETERMINISM IS THE POINT, and it is a day-one design decision rather than a property to retrofit. Every quantity here is an INTEGER. No float, no libm, no wall clock, no process, no randomness. A match is therefore a pure function of its inputs and replays bit-identically on any machine, which is what makes a result verifiable by recomputation. See the sine table note below.

UNITS Distance/velocity/energy: fixed-point, scale 256 (8 fractional bits). Angles: BINARY ANGLE, 0..255 where 256 is a full turn (1 unit = 1.40625 deg). Wrap is a band, never a rem, so negative angles cost nothing. Bullet power: TENTHS, 1..30, meaning 0.1 .. 3.0. Sine: scaled by 32768.

TURN ORDER is fixed and load-bearing (a reordering is a rules change, so it changes the engine hash and starts a new season): 1 rotate 2 accelerate and move and resolve walls 3 fire 4 advance bullets and resolve hits 5 scan 6 cool guns

Summary

Functions

alive(Arena)

-spec alive(#arena{turn :: non_neg_integer(), tanks :: list(), bullets :: list(), scans :: list()}) ->
               [#tank{id :: term(),
                      x :: integer(),
                      y :: integer(),
                      heading :: 0..255,
                      gun :: 0..255,
                      radar :: 0..255,
                      vel :: integer(),
                      energy :: integer(),
                      gun_heat :: integer(),
                      dead :: boolean(),
                      damage_dealt :: integer()}].

arena_size()

-spec arena_size() -> {integer(), integer()}.

cos(A)

-spec cos(integer()) -> integer().

delta(Tank, Tank)

-spec delta(#tank{id :: term(),
                  x :: integer(),
                  y :: integer(),
                  heading :: 0..255,
                  gun :: 0..255,
                  radar :: 0..255,
                  vel :: integer(),
                  energy :: integer(),
                  gun_heat :: integer(),
                  dead :: boolean(),
                  damage_dealt :: integer()},
            #tank{id :: term(),
                  x :: integer(),
                  y :: integer(),
                  heading :: 0..255,
                  gun :: 0..255,
                  radar :: 0..255,
                  vel :: integer(),
                  energy :: integer(),
                  gun_heat :: integer(),
                  dead :: boolean(),
                  damage_dealt :: integer()}) ->
               {integer(), integer()}.

dist(_, _)

-spec dist({integer(), integer()}, {integer(), integer()}) -> integer().

finished(Arena)

-spec finished(#arena{turn :: non_neg_integer(), tanks :: list(), bullets :: list(), scans :: list()}) ->
                  boolean().

fp(N)

-spec fp(integer()) -> integer().

in_arc(_, A0, D, BeamMin)

-spec in_arc({integer(), integer()}, integer(), integer(), integer()) -> boolean().

new(Starts)

-spec new([{term(), integer(), integer(), integer()}]) ->
             #arena{turn :: non_neg_integer(), tanks :: list(), bullets :: list(), scans :: list()}.

sin(A)

-spec sin(integer()) -> integer().

step(Arena, Intents)

-spec step(#arena{turn :: non_neg_integer(), tanks :: list(), bullets :: list(), scans :: list()},
           [{term(),
             #intent{turn_body :: integer(),
                     turn_gun :: integer(),
                     turn_radar :: integer(),
                     accel :: integer(),
                     fire :: integer()}}]) ->
              #arena{turn :: non_neg_integer(), tanks :: list(), bullets :: list(), scans :: list()}.

trace_hash(Arena)

-spec trace_hash(#arena{turn :: non_neg_integer(), tanks :: list(), bullets :: list(), scans :: list()}) ->
                    binary().

unfp(N)

-spec unfp(integer()) -> integer().

wrap(A)

-spec wrap(integer()) -> 0..255.