Secrets of the 1UP House
In this 2-part series, I’ll be presenting what is probably the most in-depth analysis of the New Super Mario Bros. Green Toad House minigame on the internet.
Part 1 (this one) will describe how the game works, and part 2 will investigate strategies for playing it. While researching for this post, I accidentally fell into the rabbit hole of analyzing NSMB’s RNG function, and that ended up becoming its own separate post. It ultimately wasn’t directly related to this series, but you can consider it a sort of “part 0.”
The game
If you’re unfamiliar with the 1UP minigame, give the video below a quick watch (courtesy of my friend Meatball132):
There are six blocks. Three contain single 1UP mushrooms, one contains three of them, one contains an “x2” card that doubles whatever you’ve won so far, and one contains a Bowser card that ends the game. The block order is random and there’s no “tell,” so this is purely a guessing game.
Implementation basics
The contents of each block are chosen while the room is being loaded, before it even appears on-screen. The Toadsworth actor itself acts as a sort of minigame-coordinator sprite responsible for arranging the cards, which I personally find to be a hilariously pointlessly skeuomorphic design choice.
He randomly places the 3UP card into one of the blocks, randomly places the x2 card into one of the five remaining blocks, and finally randomly places the Bowser card into one of the four remaining blocks1. The three leftover blocks implicitly receive single 1UPs.
…Blog post over, right? What more could there be to say about something that simple? Well, it turns out that there are three separate factors that make the game less than fully random. I’ll describe them in order of least to most severe.
Complication 1: choosing a block
Placing a card in one of the six blocks naturally involves choosing a random number 1 through 6 – or rather, 0 through 5, because computers. Here’s the (decompiled) line of code Toadsworth uses to accomplish that:
int choice = (6 * (rand_nsmb() & 0x7fff)) >> 15;
rand_nsmb
can return any of 4294967296 different values, and that number isn’t evenly divisible by 6. Since that range can’t be divided into 6 equally sized portions, some choices are inevitably going to be slightly more probable than others. With the code above (which also discards 17 of the 32 bits of randomness, which doesn’t help either2), the probabilities of picking the first or fourth positions are about 0.003% higher than the others.
Now, obviously, a 0.003% bias is completely negligible – so much that I won’t even be factoring it into further calculations at all3. I still find it kind of interesting theoretically, though.
The other two complications, though, do affect gameplay to significant degrees.
Complication 2: Toadsworth takes pity
If the first block you hit contains the Bowser card or the x2 card, Toadsworth discreetly switches that card with one of the 1UP cards just before the animation plays. This makes it impossible to reveal either of those cards on the first turn, guaranteeing that you’ll always win at least one 1UP, and that the x2 card (if found) will always double something.
Unlike the other factors affecting the minigame’s randomness, this one is very intentional.
Complication 3: handling card collisions
Something I’ve neglected to mention up to this point is how Toadsworth avoids putting multiple cards into the same block. After all, if you just pick a random number 0-5 three times, you could get, say, [1, 1, 4], but obviously the 3UP and x2 cards can’t both be placed in the second block.
Let’s quickly look at some possible correct solutions to this, before seeing Nintendo’s actual solution.
Restricting the range
One way to solve this would be to realize that once you’ve picked the 3UP card location, instead of picking a random number 0-5 for the x2 card, you should really pick a random number 0-4, since there are only 5 spots left. Then, if the number you get is greater than or equal to the first, add 1.
And just like that, your number is now in the range [0, 3UP card location - 1] ∪ [3UP card location + 1, 5], with a proper discrete uniform distribution. You would then do the same thing to place the Bowser card, too.
Rejection sampling
Alternatively, you could use a discrete version of rejection sampling. After placing the 3UP card, pick a random number 0-5 for the x2 card. If it’s the same as the 3UP card location, try again by picking another random number 0-5. Keep doing that until you get a number that’s different. And then for the Bowser card, keep picking random numbers until you get one that matches neither of the previous two cards.
This is a little less efficient than the previous solution, since it might take more RNG calls to place the x2 and Bowser cards, but it could be simpler to program. You still get a discrete uniform distribution in the end4, so it’s a valid choice.
Nintendo’s solution
What actually happens could perhaps be described as “rejection sampling done wrong.”
After the 3UP card is placed, a random number 0-5 is chosen for the x2 card. If it matches the 3UP card location… the game adds one (wrapping around from 5 to 0 if needed).
This is bad; it makes the position immediately to the right of the 3UP twice as likely to be chosen as any of the other spots!
The Bowser card is placed in the same way: if the random number matches either of the first two, it’s incremented until it’s unique. If the x2 and 3UP are right next to each other (which has a 33% chance of happening), the spot to the right of them is three times as likely as the others (50%!) to get the Bowser card!
The pity-rule code also uses the same process to move the x2 or Bowser card, if the player hits one of those blocks first. In this case, all three of the initial card positions are considered ineligible choices.
Strategizing
Knowing how the game works now, it seems that it might be possible to come up with strategies that could, on average, improve your results. After all, some configurations are more likely to happen than others. Figuring out exactly how to do that, though, is somewhat tricky.
Stay tuned for part 2, in which I present the provably optimal strategy for this minigame!
-
To be more precise, he places the Bowser card, and then immediately forgets he did so and does it a second time. This repetition accomplishes absolutely nothing. Nintendo’s programming is great. ↩
-
It is considered good practice to discard the least-significant few bits when using a linear congruential generator (“The low-order bits of LCGs when m is a power of 2 should never be relied on for any degree of randomness whatsoever.” – Wikipedia), but Nintendo’s actually doing the opposite here by discarding the seventeen most significant bits. ↩
-
In the next blog post, I mean. This one doesn’t have very many calculations at all. ↩
-
Unless, of course, your RNG function has a bug where it might just repeat the same number over and over again. Then this strategy could make the game freeze. But no game would be silly enough to use a broken RNG function like that! Right? Right?? ↩