[HN Gopher] The gold standard of optimization: A look under the ...
       ___________________________________________________________________
        
       The gold standard of optimization: A look under the hood of
       RollerCoaster Tycoon
        
       Author : mariuz
       Score  : 102 points
       Date   : 2026-03-22 19:02 UTC (3 hours ago)
        
 (HTM) web link (larstofus.com)
 (TXT) w3m dump (larstofus.com)
        
       | sroerick wrote:
       | I had always heard about how RCT was built in Assembly, and
       | thought it was very impressive.
       | 
       | The more I actually started digging into assembly, the more this
       | task seems monumental and impossible.
       | 
       | I didn't know there was a fork and I'm excited to look into it
        
         | mikkupikku wrote:
         | Macros. Lots of macros.
        
           | timschmidt wrote:
           | And presumably generous use of code comments
        
       | HelloUsername wrote:
       | Fun read, thx! I'd also recommend more about RCT:
       | 
       | "Interview with RollerCoaster Tycoon's Creator, Chris Sawyer
       | (2024)" https://news.ycombinator.com/item?id=46130335
       | 
       | "Rollercoaster Tycoon (Or, MicroProse's Last Hurrah)"
       | https://news.ycombinator.com/item?id=44758842
       | 
       | "RollerCoaster Tycoon at 25: 'It's mind-blowing how it inspired
       | me'" https://news.ycombinator.com/item?id=39792034
       | 
       | "RollerCoaster Tycoon was the last of its kind [video]"
       | https://news.ycombinator.com/item?id=42346463
       | 
       | "The Story of RollerCoaster Tycoon"
       | https://www.youtube.com/watch?v=ts4BD8AqD9g
        
       | fweimer wrote:
       | What language is this article talking where compilers don't
       | optimize multiplication and division by powers of two? Even for
       | division of signed integers, current compilers emit inline code
       | that handles positive and negative values separately, still
       | avoiding the division instruction (unless when optimizing for
       | size, of course).
        
         | cjbgkagh wrote:
         | It was written in assembly so goes through an assembler instead
         | of a compiler.
        
           | rawling wrote:
           | I assume GP is talking about the bit in the article that goes
           | 
           | > RCT does this trick all the time, and even in its OpenRCT2
           | version, this syntax hasn't been changed, since compilers
           | won't do this optimization for you.
        
         | shakow wrote:
         | That's what I would have thought as well, but looks like that
         | on x86, both clang and gcc use variations of LEA. But if
         | they're doing it this way, I'm pretty sure it must be faster,
         | because even if you change the x4 for a <<2, it will still
         | generate a LEA.
         | 
         | https://godbolt.org/z/EKj58dx9T
        
           | adrian_b wrote:
           | They use LEA for multiplying with small constants up to 9.
           | 
           | For multiplying with powers of two greater or equal to 16,
           | they use shift left, because LEA can no longer be used.
        
       | londons_explore wrote:
       | > it turns an optimization done out of technical necessity into a
       | gameplay feature
       | 
       | And this folks is why an optimizing compiler can never beat
       | sufficient quantities of human optimization.
       | 
       | The human can decide when the abstraction layers should be
       | deliberately broken for performance reasons. A compiler cannot do
       | that.
        
         | timschmidt wrote:
         | Agreed. It really requires an understanding of not just the
         | software and computer it's running on, but the goal the
         | combined system was meant to accomplish. Maybe some of us are
         | starting to feed that sort of information into LLMs as part of
         | spec-driven development, and maybe an LLM of tomorrow will be
         | capable of noticing and exploiting such optimizations.
        
       | applfanboysbgon wrote:
       | > Imagine a programmer asking a game designer if they could
       | change their formula to use an 8 instead of a 9.5 because it is a
       | number that the CPU prefers to calculate with. There is a very
       | good argument to be made that a game designer should never have
       | to worry about the runtime performance characteristics of binary
       | arithmetic in their life, that's a fate reserved for programmers
       | 
       | Numeric characteristics are _absolutely_ still a consideration
       | for game designers even in 2026, one that influences what numbers
       | they use in their game designs. The good ones, anyways. There
       | are, of course, also countless bad developers /designers who
       | ignore these things these days, but not because it is free to do
       | so; rather, because they don't know better, and in many cases it
       | is one of many silent contributing factors to a noticeable
       | decrease in the quality of their game.
        
         | edflsafoiewq wrote:
         | Examples?
        
           | andai wrote:
           | https://en.wikipedia.org/wiki/Nuclear_Gandhi
           | 
           | From what I heard, there was a Civilization game which
           | suffered from an unsigned integer underflow error where
           | Gandhi, whose aggression was set to 0, would become "less
           | aggressive" due to some event in the game, but due to integer
           | underflow, this would cause his aggression to go to 255,
           | causing him to nuke the entire map.
           | 
           | The article says this was just an urban legend though. Well,
           | real or not, it's a perfect example of the principle!
        
             | luaKmua wrote:
             | Indeed an urban legend. Sid Meier himself debunked in his
             | memoir, which is a pretty great read.
        
           | Waterluvian wrote:
           | Not really an example that proves any point, but one that
           | comes to mind from a 20-year-old game:
           | 
           | World of Warcraft (at least originally) encoded every item as
           | an ID. To keep the database simple and small (given millions
           | of players with many characters with lots of items): if you
           | wanted to permanently enchant your item with an upgrade, that
           | was represented essentially as a whole new item. The item was
           | replaced with a different item (your item + enchant).
           | Represented by a different ID. The ID was essentially a
           | bitmask type thing.
           | 
           | This meant that it was baked into the underlying data
           | structures and deep into the core game engine that you could
           | _never_ have more than one enchant at a time. It wasn 't like
           | there was a relational table linking what enchants an item in
           | your character's inventory had.
           | 
           | The first expansion introduced "gems" which you could socket
           | into items. This was basically 0-4 more enchants per item.
           | The way they handled this was to just lengthen item Ids by a
           | whole bunch to make all that bitmask room.
           | 
           | I might have gotten some of this wrong. It's been forever
           | since I read all about these details. For a while I was
           | obsessed with how they implemented WoW given the sheer scale
           | of the game's player base 20 years ago.
        
           | hcs wrote:
           | Not the same thing but I was reminded of a joke about the
           | puzzle game Stephen's Sausage Roll:
           | 
           | > I have calculated the value of Pi on Sausage Island and
           | found it to be 2.
           | 
           | https://web.archive.org/web/20240405034314/https://twitter.c.
           | ..
        
           | mort96 wrote:
           | I think Minecraft's lighting system is a good example: there
           | are 16 different brightness levels, from 0 to 15. This allows
           | the game to store light levels in 4 bytes per block.
           | 
           | Similarly, redstone has 16 power levels: 0 to 15. This allows
           | it to store the power level using 4 bits. In fact, quite a
           | lot of attributes in Minecraft blocks are squeezed into 4
           | bits. I think the system has grown to be more flexible these
           | days, but I'm pretty sure the chunk data structure used to
           | set aside 4 bits for every block for various metadata.
           | 
           | And of course, the world height used to be at 255 blocks.
           | Every block's Y position could be expressed as an 8-bit
           | integer.
           | 
           | A voxel game like that is a good example of where this kind
           | of efficiency really matters since there's just _so much
           | data_. A single 16 _16_ 256 chunk is 65.5k blocks. If a game
           | designer says they want to add a new light source with
           | brightness level 20, or a new kind of redstone which can go
           | 25 blocks, it might very well be the right choice to say no.
        
           | ErroneousBosh wrote:
           | Going way back into history, the Alesis MIDIVerb reverb unit
           | had a really simple DSP core made out of discrete logic
           | chips. It could add a memory location to an accumulator and
           | divide it by two, invert it, add it and divide it by two, or
           | store it in ram either inverted or not and divide the
           | accumulator by two.
           | 
           | Four instructions, in about eight chips.
           | 
           | By combining shifts and adds Keith Barr was able to devise
           | all the different filter and delay coefficients for 63
           | different reverb programs (the 64th one was just dead
           | passthrough).
        
         | timschmidt wrote:
         | Absolutely. I have written a small but growing CAD kernel which
         | is seeing use in some games and realtime visualization tools (
         | https://github.com/timschmidt/csgrs ) and can say that
         | computing with numbers isn't really even a solved problem yet.
         | 
         | All possible numerical representations come with inherent
         | trade-offs around speed, accuracy, storage size, complexity,
         | and even the kinds of questions one can ask (it's often not
         | meaningful to ask if two floats equal each other without an
         | epsilon to account for floating point error, for instance).
         | 
         | "Toward an API for the Real Numbers" (
         | https://dl.acm.org/doi/epdf/10.1145/3385412.3386037 ) is one of
         | the better papers I've found detailing a sort of staged
         | complexity technique for dealing with this, in which most
         | calculations are fast and always return (arbitrary precision
         | calculations can sometimes go on forever or until memory runs
         | out), but one can still ask for more precise answers which
         | require more compute if required. But there are also other
         | options entirely like interval arithmetic, symbolic algebra
         | engines, etc.
         | 
         | One must understand the trade-offs else be bitten by them.
        
         | lukan wrote:
         | "and in many cases it is one of many silent contributing
         | factors to a noticeable decrease in the quality of their game"
         | 
         | Game designers are not so constrained anymore by the limits of
         | the hardware, unless they want to push boundaries. Quality of a
         | game is not just the most efficient runtime performance - it is
         | mainly a question if the game is fun to play. Do the mechanics
         | work. Are there severe bugs. Is the story consistent and the
         | characters relatable. Is something breaking immersion. So ...
         | frequent stuttering because of bad programming is definitely a
         | sign of low quality - but if it runs smooth on the targets
         | audience hardware, improvements should be rather done
         | elsewhere.
        
           | scns wrote:
           | > it is mainly a question if the game is fun to play.
           | 
           | 10000x this. Miyamoto starts with a rudimentary prototype and
           | asks himself this. Sadly it seems for many fun is an
           | afterthought they try to patch in somehow.
        
           | sublinear wrote:
           | This way of thinking has caused at least a few prominent
           | recurring bugs I can think of.
           | 
           | Texture resolution mismatches causing blurriness/aliasing,
           | floating point errors and bad level design causing collision
           | detection problems (getting stuck in the walls), frame rate
           | and other update rates not being synced causing stutter and
           | lag (and more collision detection problems), bad illumination
           | parameters ruining the look they were going for, numeric
           | overflow _breaking everything_ , bad approximations of
           | constants also breaking everything somewhere eventually,
           | messy model mesh geometry causing glitches in texturing,
           | lighting, animation, collision, etc.
           | 
           | There's probably a lot more I'm not thinking of. They have
           | nothing to do "with the hardware", but the underlying math
           | and logic.
           | 
           | They're also not bugs to "let the programmer figure out".
           | Good programmers and designers work together to solve them. I
           | could just as easily hate on the many _criminally ugly,
           | awkward, and plain unfun_ games made by programmers working
           | alone, but I 'll let someone else do that. :)
        
             | lukan wrote:
             | Game designer != game engine designer
             | 
             | (But it definitely helps if the game designer knows of the
             | technical limits)
        
               | sublinear wrote:
               | Sorry, I'm not super familiar with professional game dev,
               | but I am familiar with professional web dev. The problems
               | seem similar, as evidenced by the constant complaining
               | here on HN about the state of the web.
               | 
               | Who formats or cleans up the assets and at least oversees
               | that things are done according to a consistent spec,
               | process, and guidelines? Is that not a game designer or
               | someone under their leadership?
               | 
               | I think in all the cases I gave, what might be completely
               | delegated to "engine design" really should be teamwork
               | with game design and art direction too. This is what the
               | top-level comment was talking about. Even when a game is
               | "well made", they just adopted someone else's standards
               | and that sucks all the soul out of it. This is a common
               | problem in all creative work.
        
               | lukan wrote:
               | It depends how big the studio is, but a job of a game
               | designer is usually not cleaning up assets. It is to
               | well, design the game. The big picture.
        
       | lefty2 wrote:
       | > The same trick can also be used for the other direction to save
       | a division:
       | 
       | > NewValue = OldValue >> 3;
       | 
       | You need to be careful, because this doesn't work if the value is
       | negative. A
        
         | whizzter wrote:
         | Most CPU's has signed and unsigned right shift instructions
         | (left shift is the same), so yes it works (You can test this in
         | C by casting a signed to unsigned before shifting).
         | 
         | The biggest caveat is that right shifting -1 still produces -1
         | instead of 0, but that's usually fine for much older game
         | fixed-point maths since -1 is close enough to 0.
        
       | bluelightning2k wrote:
       | Great write up. Thank you. Really great!
       | 
       | I was reminded of the factorio blog. That game's such a huge
       | optimization challenge even by today's standards and I believe
       | works with the design.
       | 
       | One interesting thing I remember is if you have a long conveyor
       | belt of 10,000 copper coils, you can basically simplify it to
       | just be only the entry and exit tile are actually active. All the
       | others don't actually have to move because nothing changes... As
       | long as the belts are fully or uniformly saturated. So you avoid
       | mechanics which would stop that.
        
       | youarentrightjr wrote:
       | > The same trick can also be used for the other direction to save
       | a division: NewValue = OldValue >> 3; This is basically the same
       | as NewValue = OldValue / 8; RCT does this trick all the time, and
       | even in its OpenRCT2 version, this syntax hasn't been changed,
       | since _compilers won't do this optimization for you_.
       | 
       | (emphasis mine)
       | 
       | Not at all true. Assuming the types are such that >> is
       | equivalent to /, modern compilers will implement division by a
       | power of two as a shift every single time.
        
       ___________________________________________________________________
       (page generated 2026-03-22 23:00 UTC)