💾 Archived View for thrig.me › blog › 2023 › 07 › 14 › fakerng.gmi captured on 2024-07-09 at 01:07:20. Gemini links have been rewritten to link to archived content
⬅️ Previous capture (2023-11-14)
-=-=-=-=-=-=-
There are antiquity that feature bros at dice; Achilles always beats Ajax. There are storytelling reasons for this; Achilles is the best, so therefore cannot lose, except when the plot demands it. A continent over Shakuni used dice that always rolled the desired number. More examples can doubtless be had.
Computer games sometimes feature not exactly random numbers that favor storytelling or skill over cold hard statistics; the rolls are fudged to be more in line with what a human expects, which is that a skill that activates 33 percent of the time will roughly follow the pattern of hit miss miss. A 95% skill that misses twice in a row? Fuggedaboutit!
To be fair, early random number generators were pretty terrible. Various Apple //e games always played the same at boot, or here is the RNG from rogue.
#include <stdio.h> int seed = 1; // the rogue 3.6.3 random number generator #define RN (((seed = seed * 11109 + 13849) & 0x7fff) >> 1) int coinflip(void) { return RN & 1; } int main(void) { for (int i = 0; i < 100; i++) printf("%d ", coinflip()); putchar('\n'); }
$ make badnumbers && ./badnumbers cc -O2 -pipe -o badnumbers badnumbers.c 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0
You can obtain a coinflip from this RNG, just not from the lowest bit. The regularity of the change of the lowest bit might lead one to wonder what else is broken. That rabbit hole is not a concern here.
Let us assume that we have a "good enough" RNG for a computer game. This may require some research for speed, portability, memory use, etc. though there are plenty of choices nowadays. Games generally do not need cryptographically secure numbers, but do often need reproducible numbers. Debugging is harder if you are unable to get the RNG into a correct state, versus "dungeon seed 20177 generates broken orc platoon on level 5".
So how do we fudge the numbers so that a 33 percent skill activates more like how humans expect it should? One method is to associate state with the dice roll. When a roll misses, the odds of activation are increased; when a roll hits, the odds of activation are decreased. This better prevents long runs of hits or misses, fiber for the RNG diet.
(block nil (setq *random-state* (make-random-state t)) (return)) (let ((odds 50)) (defun fire-blaster () (if (<= (random 100) odds) (prog1 t (setf odds 9)) (prog1 nil (incf odds 19))))) (let ((hit 0) (trials 10000000)) (loop repeat trials do (when (fire-blaster) (incf hit))) (format t "trooper efficiency ~f~&" (/ hit trials)))
$ sbcl --script rollem.lisp trooper efficiency 0.3337203 $ sbcl --script rollem.lisp trooper efficiency 0.3336762 $ sbcl --script rollem.lisp trooper efficiency 0.3337741
The default to-hit is 50% (beginner's luck) though on hit that drops to 9%, and with every miss the odds are increased by 19%. This works out to roughly a 33% hit ratio, though the distribution will be different than letting the RNG run wild and free. Maintaining state could be a problem if there are too many units and not enough memory? There are other ways to wrangle this—the ability could use a cooldown timer, or not everything needs a dice roll.
Another use is where you want a resource to be randomized, but not too random. Brogue in particular uses what the author calls "rubber band odds" (similar to the above adjustment) to place food. The player will not know on what levels a food ration will drop, but the drops will be fairly regular throughout the dungeon. Without the rubber band odds the RNG could on rare occasions simply not drop any food (or may drop too much food at the expense of other items); no amount of skill could win that seed. Skill within the confines of the game system, that is, if one recalls the Kobayashi Maru. Knowing the state of the RNG is a pretty powerful lever.