Precomputed Routes and Fake Physics: How Pizza Tycoon Simulated a City on a 25 MHz CPU
Source: hackernews
The article at pizzalegacy.nl documents how Pizza Tycoon’s developers built a functioning traffic simulation for a 25 MHz 486 processor. Pizza Tycoon was a 1994 DOS business simulation from Software 2000, where players built and managed pizza restaurant chains across a tile-based city. That city needed to feel inhabited: cars flowing through streets, pedestrians passing storefronts, delivery vehicles finding routes. Achieving this on hardware with roughly 25 million integer instructions per second, no hardware floating-point unit, and a 640 KB conventional memory ceiling was a genuine engineering problem, not a minor consideration.
What 25 MHz Actually Meant in 1993
The 486SX was the budget version of Intel’s 486 line. Intel stripped out the floating-point unit to create it, leaving a chip that ran integer operations efficiently but emulated floating-point in software at roughly 10 to 40 times the cost of equivalent integer math. At 25 MHz targeting 25 frames per second, you had about 40 milliseconds per frame, shared across rendering, input handling, game logic, audio, and simulation. The traffic system had to operate within whatever time remained after those other systems took their share.
DOS extended memory tools like DOS4GW let developers access more than 640 KB, but memory bandwidth was still constrained by the ISA or VLB bus and the DRAM speeds of the era. Large lookup tables paid for themselves if accessed frequently and fit within the CPU’s small on-chip cache, but only if access patterns were cache-friendly.
The Three Tiers of Traffic Simulation
Before examining technique, it helps to be precise about what traffic simulation means in a tile-based city game. There are meaningfully different approaches at meaningfully different costs.
The cheapest is scripted movement: vehicles follow fixed waypoints baked into the map. They do not pathfind, they do not react to one another, and they function as animated decoration. Many DOS-era city games used this approach for background vehicles while reserving real simulation for player-relevant entities only.
A middle tier adds local interaction: vehicles follow fixed routes but stop when blocked, wait at intersections, and yield to one another. The routes are predetermined, but emergent behavior arises from vehicle interactions and timing differences.
Full dynamic pathfinding is the most expensive tier: each vehicle holds a source and destination, computes a route through the shared road network, and navigates based on current conditions. This is what Transport Tycoon required for trains sharing track, and it was expensive enough that it occupied most of Chris Sawyer’s optimization work when he wrote that game in hand-optimized x86 assembly, also in 1994.
Pizza Tycoon’s traffic was gameplay-relevant. Customer flow affected restaurant revenue. Delivery routes determined operational efficiency. The city could not be purely decorative, which pushed the simulation toward the more expensive end of this spectrum and forced the developers to find ways to make that tractable on commodity hardware.
Precomputed Pathfinding and Flow Fields
For a city with a static road network, the expensive part of per-vehicle pathfinding is the graph search. Running Dijkstra or BFS for every vehicle on every frame is infeasible at 25 MHz. The standard solution in games of this era was to precompute pathfinding information once at map load time and store it in lookup tables indexed by tile position.
This structure is called a flow field, or navigation field. For a given destination tile, you run BFS backward from the destination across the road network. Each tile stores the direction a vehicle should move to reach that destination optimally. At runtime, a vehicle checks its current tile, reads the precomputed direction, and moves. The expensive search runs once at load time; per-frame cost per vehicle drops to a single memory lookup and a position update.
Storage cost is proportional to map size times number of destinations. A 64x64 tile map with four distinct delivery destinations requires 16,384 bytes per destination, well within reach even under DOS memory constraints. If destinations change dynamically, the field needs recomputation, but in a business sim with stable restaurant locations, this is an infrequent event.
The key precondition is a static road network. Pizza Tycoon’s city layout was fixed for each map, which made precomputed fields viable. Games where roads are built dynamically during play, like Transport Tycoon, require either incremental field updates or selective path recomputation, which is substantially harder to implement correctly.
Time-Slicing and the Entity Budget
Precomputed paths reduce per-vehicle cost, but the total vehicle count in a city can still exceed what fits in a single frame’s time budget. Time-slicing addresses this by dividing vehicles into groups and updating a different group each frame.
At 25 FPS with 40 milliseconds per frame, allocating 5 milliseconds to traffic AI is a reasonable ceiling. If each vehicle update costs 50 microseconds, a table lookup plus position update with integer arithmetic on a 486, that budget handles 100 vehicles per frame. Spread across 4 frames of time-slicing, the simulation maintains 400 vehicles in total while each one updates at roughly 6 Hz rather than 25 Hz. At tile-based movement speeds, 6 updates per second produces movement that appears smooth during normal play.
The visible artifact of time-slicing is that vehicles advance in discrete steps at low update rates. DOS-era city games with this design often had traffic that looked slightly mechanical when examined closely; vehicles moved in small jumps rather than flowing continuously. At normal play speed and camera distance, the illusion held well enough that players rarely noticed.
Off-screen vehicles could be updated even less frequently or handled with a simplified model entirely. Only vehicles near the active viewport need full simulation fidelity, since the player cannot see the difference for anything beyond the visible area.
Fixed-Point Arithmetic: The FPU That Wasn’t There
With software floating-point 10 to 40 times slower than integer operations, any computation in the traffic system’s hot path needed integer arithmetic exclusively. The standard technique was fixed-point representation.
A 16.16 fixed-point number packs a 16-bit integer part and 16-bit fractional part into a 32-bit integer. Addition and subtraction cost the same as integer operations with no overhead. Multiplication requires a 32-bit by 32-bit multiply producing a 64-bit intermediate result, followed by a 16-bit right shift to normalize. On the 486, the multiply instruction alone took over a dozen clock cycles, but this was still several times faster than any emulated floating-point operation and kept the compiler from reaching for the FPU emulation library.
For direction and trigonometry, the approach was precomputed tables. A 256-entry sine and cosine table computed once at startup and stored as 16.16 fixed-point integers lets you index any angle with a single byte and retrieve the value in one memory access. With 256 angular steps covering a full circle, you get approximately 1.4-degree resolution, which is far more precision than tile-based movement ever requires since meaningful directions are multiples of 45 degrees.
What SimCity Did Instead
SimCity, from its 1989 original through SimCity 2000 in 1993, took a radically different approach that illustrates what Pizza Tycoon was doing by contrast. SimCity did not simulate individual vehicles at all. Its traffic model computed per-tile traffic density by propagating zone connectivity information across the road network: how many trips would logically pass through each tile given the surrounding residential, commercial, and industrial zone activity.
The animated cars in SimCity were decorative. The traffic jams players saw were just high-density tiles rendered with congestion graphics, not emergent behavior from vehicle interactions. This made SimCity’s traffic model cheap, scalable to large cities, and entirely disconnected from any individual vehicle’s journey.
Pizza Tycoon needed individual vehicles to have meaningful journeys. A delivery driver taking the wrong route had tangible gameplay consequences. The SimCity aggregate model was not an option, which is why the flow field and time-slicing approach matters: it is a deliberate attempt to do genuine individual simulation within a severe budget, rather than substituting an aggregate approximation that happens to look similar on screen.
Transport Tycoon, Sawyer’s contemporary work in 1994, handled the per-vehicle simulation problem by writing everything in hand-optimized x86 assembly with no C compiler involved. That approach extracted performance the compiler could not, but it was a one-person heroic effort that did not generalize to typical development teams. Pizza Tycoon found a different answer using data structure design rather than micro-optimization.
Why Flow Fields Keep Coming Back
The algorithmic insight behind precomputed navigation fields is durable across hardware generations. The same approach appeared in Supreme Commander in 2007 and Planetary Annihilation in 2014, scaled to handle hundreds of simultaneous units on modern hardware. The fundamental tradeoff is unchanged: BFS from destination costs proportional to map size once at precomputation time, while per-agent search costs proportional to map size per agent per path request. When agent counts are large and the map is static, precomputing the field wins regardless of whether you are working with 25 MHz or 25 GHz.
Flow fields are also well-suited to GPU acceleration, since propagating a distance gradient across a grid is an embarrassingly parallel operation. The technique that DOS developers used because they had no alternative turns out to be genuinely well-structured for modern parallel execution as well.
The pizzalegacy.nl article is a record of how specific developers navigated specific constraints in 1993, making explicit choices that modern development environments let you defer indefinitely. Reading that kind of technical retrospective is useful not because the hardware constraints apply today, but because reasoning that held up under extreme constraint tends to reflect something true about the problem structure rather than something incidental to the platform. The precomputed field insight is not a 486-era hack; it is a correct observation about the asymmetry between building a navigation structure and querying it, and that asymmetry has not changed.