💾 Archived View for thrig.me › blog › 2024 › 02 › 05 › some-random-things.gmi captured on 2024-05-10 at 11:10:00. Gemini links have been rewritten to link to archived content
⬅️ Previous capture (2024-03-21)
-=-=-=-=-=-=-
First, pick your algorithm well. Some are bad, especially old ones from when computers were not very powerful.
#define RN_MAX 0x7fff #define RN (((seed = seed * 11109 + 13849) & RN_MAX) >> 1)
However, if all you have is an old (or small) computer, and you are writing a quick game in assembly, then it may make sense to use something terrible, provided you know the pitfalls involved.
rand_seed: xor ax, ax int 0x1a ; fn: system time mov [seed], dx ret ; the "RNG" from rogue 3.6.3 rand_value: ; in=bx, out=dx (or dl) mov ax, [seed] mov cx, 11109 mul cx add ax, 13849 mov [seed], ax ror ax, 1 xor dx, dx div bx ret seed: dw 0
Newer algorithms may be bad in that they may take up too much memory or CPU. If cryptography, the algorithm should be suited to that. If shooting Xorglaxian Crusaders or rolling some dice to see if the Hero falls in love with the Dragon, then something less expensive may do, unless you have competitive players who try to guess the game seed.
https://www.pcg-random.org/posts/some-prng-implementations.html
SWAGGINZZZ with her RNG-predicting AWS-cluster of monster computers
On the other hand, those just starting out may want a language with "batteries included" and to use whatever RNG it ships with plus plenty of worked and hopefully tested examples. Or maybe you enjoy debugging why your custom code is only generating maces and not any other weapons?
Small, fast, not obviously broken, appears to be public domain code. Good enough for a smolgame? Probably this needs a few more functions such as "roll" for dice rolls and "one_in" for 1 in N odds of something happening, maybe also floating point, etc.
A cryptographic RNG may be a good way to seed a faster RNG. Read some bytes from /dev/urandom, or on OpenBSD use arc4random(3). Or RDRAND if you trust the on-chip hardware. Higher level interfaces may use RDRAND among other sources of entropy.
For games where money and competition is less involved the seed may be derived from the current date (e.g. YYYYMMDD) so that different players using the same software can play the same seed and then discuss the results. Someone could practice such a seed in advance, so this is open to abuse.
$ date +%Y%m%d 20240205
For some games it may make sense to seed multiple generators so that level generation uses a distinct seed from the one for combat. Reasons for this include making the combat RNG impossible to guess from looking at what the level layout is doing, or so that the next level generated does not depend on the actions taken during the previous level. Some games will simply generate all the levels in advance.
Dragon Half Ending (with apologies to Beethoven)
static const char noise[] = "..,`':;~+=< _ij\"^\\l(amxvu04PYW"; inline static char rndchar(void) { size_t index = 0; size_t len = sizeof(noise) / sizeof(char); while (1) { size_t x = jsf_below(8); index += x; if (x < 5) break; } if (index >= len) index = 0; return noise[index]; }
This code favors "less dense" characters early in the "noise" list, though will sometimes select "heavier" characters at the end. The characters are somewhat arbitrarily arranged. One should test these things; for visual noise in a game one wants something that looks good enough and isn't too expensive to calculate. It may also be good to tally up a lot of iterations to see what an average noise profile looks like, and from there to tune the cut-off points and list of noise characters as need be.
$ cc -c -o jsf.o jsf.c $ cc -o noisetally jsf.o noisetally.c $ ./noisetally | tally | sed 20q 2565798 . 1252794 , 1248885 ' 1247226 ` 468391 = 468255 + 467982 ~ 332502 < 312736 ; 214565 176668 j 158742 " 156457 i 156294 : 126316 ^ 117453 _ 83264 \ 61350 a 60450 l 57877 m
A more formal way to do this would be to better characterize how many bits a character of a font turns on, and then to sort by that for character density. Probably this code has already been done somewhere in tools like chafa, which is what (indirectly) inspired all this noise. (The space or " " character is not early in the somewhat-sorted-by-character-density list as it is used to sometimes overwrite already existing characters on the screen, but not too often.)
character art facsimile generator
Another idea might be to use "heavier" characters more often more towards the bottom of the screen instead of placing the characters into random rows and columns.
$ cc -o noiseshow jsf.o noiseshow.c -lncurses ...
And a random result.
` < . ` _ ' ^ . . ` ` , ' 0. (, , . . + ' . = x . .` ,.,' . , ` ( ` ' ; : j < ^ . ` , + ^ . .j `. ` . . ~. . +, , , ~ . ' '. ,. ' .= ` , , ; . j a ' .`l,=` .' ` ' . < ^. . = . +' . ` . , j . . . ` ` . ` . . ' . = ` . ' .. , ( = . `, . . ^ + j. ` = = ` `, ' _ + . = ; a ` . ~ . ', ` " . ~ ' _ ` = ` ' : . . ^ : . \ < . ; , : , `u +. ~ + . . ~ m .`= .` '. < j = < . . . ' + ' ` ` .l `= , `= < , ~,. ` .' ` ~ i ' . : m' . < . ` + ` ` , " , , + . + ` . < . ,+ ` . . . . + . `
And a different version where the index influences what line the character appears on, though with some randomization so that certain characters do not appear only on certain lines.
. . . . . . . . .. . . . . .. , . .. . , , . ` . . . `. . . ` ` . ,.` . `` .. .'` ` . ` . ` . . .`. ` ` ' . . . . . . . . ` ' , ,,'. ` ' , . . , ' .. , . , '. ~ . . . ,. ;: '` , . '. . ` . ' .. ~,` ' ~ . ''` . '= '. ` , . '; , ~. ,.` '; ` .~ ' . . ` ~ , , .. ` . ` ` + `'~ < ``' ~ . '~ , ' = + ~ ~ , ` ' , ` ` , ` + ' ` ':` ` ~_ ` +~ i + + ~ = ~ < _ < = : < ; i < +< + = < " + ^^ + " = =" ^ = i " < = < < < i < _ ^ ( a a j