Deterministic Physics & Simulation

To support trustless blockchain verification (Proof of Execution), CrawlCipher’s simulation engine must be 100% deterministic. The exact same sequence of input frames applied to the same seed must produce the exact same final game state, regardless of the host hardware or operating system.


1. Floating-Point Restrictions

In standard game engines, positions and velocities are represented using floating-point types (float or double). However, floating-point math is notoriously non-deterministic across different CPUs:

  • Intel/AMD processors may use x87 80-bit float registers or SSE 64-bit instructions, resulting in slightly different rounding values.
  • ARM processors handle floating-point denormals (extremely small numbers close to zero) differently than x86 processors.
  • Compiler optimizations (like /fp:fast in C++ or JIT optimization in .NET) can reorder operations, modifying precision.

Solution in CrawlCipher:

To prevent these desynchronizations, the Core C# Engine completely bans the use of floats and doubles in physics and pathfinding calculations.

  • Coordinates: Grid positions are strictly integer-based 2D vectors (Vector2Int or simple int X, Y).
  • Speeds/Dividers: Speed rules (e.g. Snail speed) are processed using integer divisions and tick counters rather than delta-time multipliers (e.g., a Snail moves once every 2 ticks instead of multiplying position by 0.5 * deltaTime).

2. Seeded Random Number Generation

Standard random functions (like C#‘s default new Random()) initialize using the current system time, producing unpredictable outputs.

Deterministic Seeding:

CrawlCipher isolates all random factors (snail movements, item spawns, bot steering decisions) using a single instance of C#‘s System.Random initialized with a static seed:

// Engine initialization
_rng = new Random((int)config.ExternalSeed);

On Testnet, this seed is generated by hashing the latest block hash retrieved from Stellar Horizon, ensuring that neither the player nor the validator can predict the spawn layout before the match officially begins.


3. Fixed-Timestep Update vs. Render Loops

In normal action games, the game physics are updated based on the frame time (deltaTime). If the player’s frame rate drops, physics ticks get larger, which can lead to collision glitches and non-deterministic replays.

Isolated Loops:

CrawlCipher separates the visualization loop from the simulation loop:

  1. Render Loop (Rust TUI): Executes as fast as possible (60 FPS) to capture keyboard inputs and draw the terminal character buffers.
  2. Simulation Loop (C# Engine): Advances only when Update(gamePtr) is explicitly called by the TUI. The TUI calls this at a fixed interval (e.g. every 100ms for a 10Hz tick rate).
  3. Input Accumulation: During the 100ms interval, any directional key presses are accumulated (e.g., pressing Up and Right is accumulated to NorthEast). This accumulated vector is submitted to the engine just before the Update tick occurs.

Because the engine advances in discrete, fixed-step increments, the simulation is completely decoupled from rendering lag, making replay files perfectly audit-safe.