Sunday, 19 January 2014

How chance in games is rarely just a roll of the dice

Games contain many forms of chance. From simply selecting a random character or level to play, to random pick-ups and even completely procedural worlds: chance, luck and randomisation play a huge role. While developing Awesomenauts we have experienced this first hand, especially in the various versions of Leon's crits, which has been changed several times in patches during the past 1.5 years. Last week I mostly talked about the psychology of crits, and today I am going to look at chance in games in general.

When a programmer is told to implement a random for something, he will often simply use std::rand() or something similar and that's it. However, in practice it turns out that both players and designers rarely really want a truly random chance.

A good example of this can be found in level selection in Awesomenauts: in a practice match there are four levels to chose from, and there is a 'random' button to select random levels. With a true random, the random button might result in playing the same level several times in a row. There is a small chance that a player gets the same level 4 times in a row (1.5625%, to be exact), and even 10 times the same level in a row is possible. When this happens, both players and designers start to voice complaints like “the random is not random, it always selects the same map”. Of course, in a truly random dice roll, the chances of throwing a number are completely independent of what was thrown before that, so even a million times the same value in a row can happen. The chance of that happening is just really small.



So what every game programmer needs to realise, is that when a designer asks for random, he rarely asks for a complete random. The random usually needs some extra logic to keep unwanted situations from happening. In Awesomenauts, the game remembers which map you last played and does not select it again for the next match (although if you join matches, you might still join several matches in a row with the same map). Similarly the music player remembers the last four songs it played and does not select those again when it chooses the next song to play. And I imagine that in a random dungeon generator it is likely not desirable to put instances of the same room next to each other.

An important part of random is human perception. Humans are exceptionally good at recognising patterns. In fact, humans are so good at this that they often recognise patterns where there are none. Noteworthy situations are remembered, while other situations are not. Astrology is for a large part based on this. If only one out of ten predictions turns out to be correct, many people will tend to remember that one correct prediction and not the nine false ones, making it possible for charlatans to pass for real predictors of the future.

Something similar goes for the perception of random in games. We have had numerous reports from players that the map they dislike most is selected much more often by the random map selection. However, every player who reports this reports it for a different map, and our random is just fine. What really happens there, is that people remember every time they get the map they don't want, and don't really remember what other maps they played recently.

Human psychology is therefore an important part in designing random. A great example of this can be found in one of my favourite game series: Civilization. Sid Meier did a hilarious presentation on how they modified their random in Civilization Revolution. One of the things they did is that if a unit has 90% chance to win, this is treated as 100%, because it turned out that it always felt unreasonable to lose when the win chance was 90%. Another trick they did is that if a number of 50% battles in a row are all lost, then at some point the next one is automatically won, because it simply feels unfair to lose so often in a row.

Of course, with a mechanic like that it is important to either keep players from knowing it works like that, or to keep a bit of random in there, because otherwise knowing how this works will result in exploitable tactics. If there is one thing we learned during development of Awesomenauts and Swords & Soldiers, it is that if something can be abused, it always will!



Inspired by the Civilization article, we started playing with Leon's crit chance. The original implementation we had for this was simply a clean chance. However, this sometimes resulted in having two or three crits in a row, which is incredibly powerful. Dying from this felt unfair, because it did so much damage that there was little opportunity to get away from it.

To solve this we modified the crit chance to never happen twice in a row, and also to never fail ten times in a row. This way the crits are still random, but the situations that feel unfair don't happen anymore.

This worked fine and had the desired result, but what we did not realise is that it massively changes the actual crit chance! With a 15% crit chance, the chance of it missing 10 times in a row is a surprisingly high 19.7%. Adding a guaranteed extra crit so often increases the crit chance significantly! So in that particular patch we accidentally buffed Leon a lot, making him pretty overpowered.

We did not realise we had done this until players started counting. They quickly noticed that Leon had become a lot stronger, but we simply didn't believe them. To convince us that something was wrong, a couple of players performed several hundred attacks in a row and counted how many crits they got. Even then we still didn't believe them at first, but once we understood what was happening here, we modified the crit chances to be the same as before again, including the extra rules for consecutive hits.


Image by Awesomenauts player 'Offline' (I think).

This brings me to the end of this blogpost. As the various topics I have discussed today have shown, there is much more to chance, luck and random in games than just using pure random functions. Whenever random is involved, the designer and programmer should always consider what they want exactly, since in practice it turns out that a true random is quite rarely wanted.