Biblyon the Great

This zine is dedicated to articles about the fantasy role-playing game Gods & Monsters, and other random musings.

Gods & Monsters Fantasy Role-Playing

Beyond here lie dragons

How random is Python’s random?

Jerry Stratton, March 20, 2011

Computers have a poor reputation for randomness, and with good reason. In the old days, randomness wasn’t taken seriously. In order to get a random number the system might poll some non-random aspect of the hardware. Those whose programmers understood some mathematics might use an algorithm, but they would reset the algorithm every time the computer started up, or, worse, every time a program started up, resulting in the same series of “random” numbers every time a program was run.

Nowadays you shouldn’t have to worry about that. The reason is security: modern security relies heavily on getting truly random numbers out of the computer’s random algorithms. This has resulted in a lot of research into computer-friendly random algorithms. Python’s random functions are able to leverage this research.1 You should have no problem using your computer’s random number generators for gaming purposes nowadays.

The default random number generators in most programming languages are not cryptographically-appropriate random, however.2 The reason for this is that computer programs are bound by predictability: programmers want predictability, even when they say they want randomness.

Imagine, for example, that you’re animating a film clip in a 3D renderer. You carefully place all of the major components of the scene, but you also have a flock of birds flying in the background. You outline the path that the flock will take, but after you render the video, the birds are far too uniform. They look more like a smooth amusement park ride than a flock of individual creatures. You might say they look like a railroaded adventure.

So you add some randomness to each individual bird’s flight path; each bird follows the basic flight path of the flock, but each moves left, right, up and down by some random amount each frame of the video. You don’t want to individually plot every single member of the flock, you just want them to act like birds. A little random variation is fine.3

But when you look at the film, you see that some of the birds are flying through a telephone pole. So you make some minor adjustments to the flight path and try again, and this time it’s great.

So you make your film and you send it off to the producers, and they say, awesome! Let’s make a high-definition version for the theaters. So you re-render the film… and the birds are moving in different directions this time, because it’s random! Every time you re-render the film, the birds move differently.

The solution, and this is often enforced by the renderer, is to require you to “seed” a random number generator that emulates statistical tests for randomness but which produces results from a series of artificially—that is, pseudo—random numbers. Python uses the Mersenne twister. This algorithm produces 219937-1 “random” results before repeating itself. That’s the number “4” followed by 6,001 digits.4 When you ask for a random number, or a random choice within a list, Python “seeds” this long list by creating a random starting point for the algorithm, and then chooses each successive number from the algorithm’s “list”.

By default, you let Python choose your seed for you. But if you give the random number generator a seed, it will produce the same random numbers each time you give it that seed. Thus, you can use randomness to make a better flock without fear of the birds acting differently each time you render the scene. Persistence of Vision uses this method to give you, as a 3D artist, non-random pseudorandomness.

In the examples I’ve provided so far, we have not specified a seed, so the computer chooses a seed randomly. This makes our computer-generated rolls, for all practical purposes, fully random. But you can specify a seed if you want to see this phenomenon in action, and thus get the same random numbers every time.

[toggle code]

  • #!/usr/bin/python
  • import optparse
  • import random
  • parser = optparse.OptionParser()
  • (options, args) = parser.parse_args()
  • if not args:
    • args = [1]
  • for dieCount in args:
    • dieCount = int(dieCount)
    • total = 0
    • dice = []
    • for counter in range(dieCount):
      • die = random.randrange(6)+1
      • total = total + die
      • dice.append(die)
    • print total,
    • if dieCount > 1:
      • print ':', dice
    • else:
      • print

Save this as die6, make it executable, and you can run it as ./die6. You’ll get a random sequence of d6 rolls every time. You can roll up some stats using:

  • $ ./die6 3 3 3 3 3 3
  • 8 : [1, 5, 2]
  • 7 : [4, 2, 1]
  • 7 : [1, 5, 1]
  • 13 : [5, 4, 4]
  • 11 : [5, 2, 4]
  • 9 : [2, 4, 3]

Now, add one line to the code:

[toggle code]

  • #!/usr/bin/python
  • import optparse
  • import random
  • parser = optparse.OptionParser()
  • (options, args) = parser.parse_args()
  • if not args:
    • args = [1]
  • random.seed(616)
  • for dieCount in args:
    • dieCount = int(dieCount)
    • total = 0
    • dice = []
    • for counter in range(dieCount):
      • die = random.randrange(6)+1
      • total = total + die
      • dice.append(die)
    • print total,
    • if dieCount > 1:
      • print ':', dice
    • else:
      • print

I can now predict what your stats are: 9, 7, 6, 11, 14, and 12.5

This is what makes this particular algorithm unsafe for cryptography: if a hacker can determine where in the sequence you were when you generated your random numbers, they can predict what those numbers are. For gaming purposes, however, this is a non-issue. Unless your players are mathematical savants of unearthly power, they are not going to be able to predict where in that series you are, nor will it matter, because by default you get a different seed each time you “roll the die”.6

That said, if you let them roll their own dice programs, you might consider looking at the code. Here’s a variation that lets you specify your own seed:

[toggle code]

  • #!/usr/bin/python
  • import optparse
  • import random
  • parser = optparse.OptionParser()
  • parser.add_option('-s', '--seed', type='int')
  • (options, args) = parser.parse_args()
  • if not args:
    • args = [1]
  • if options.seed:
    • random.seed(options.seed)
  • for dieCount in args:
    • dieCount = int(dieCount)
    • total = 0
    • dice = []
    • for counter in range(dieCount):
      • die = random.randrange(6)+1
      • total = total + die
      • dice.append(die)
    • print total,
    • if dieCount > 1:
      • print ':', dice
    • else:
      • print

Seed 631 isn’t a bad set of stats. 635 is also believable with a couple of seventeens and only one dump stat. Seed 3555, on the other hand, is probably not believable. But take a look at 48191: two eighteens, two eights. You could get away with that. On the other hand, seed 122075, probably not.

  • $ ./die6 3 3 3 3 3 3 --seed 631
  • 10 : [5, 3, 2]
  • 14 : [4, 6, 4]
  • 18 : [6, 6, 6]
  • 12 : [5, 6, 1]
  • 15 : [6, 5, 4]
  • 14 : [4, 6, 4]
  • $ ./die6 3 3 3 3 3 3 --seed 635
  • 12 : [3, 5, 4]
  • 13 : [2, 5, 6]
  • 8 : [1, 2, 5]
  • 12 : [4, 6, 2]
  • 17 : [6, 6, 5]
  • 17 : [6, 6, 5]
  • $ ./die6 3 3 3 3 3 3 --seed 3555
  • 12 : [6, 4, 2]
  • 15 : [6, 4, 5]
  • 16 : [6, 4, 6]
  • 17 : [5, 6, 6]
  • 18 : [6, 6, 6]
  • 12 : [4, 3, 5]
  • $ ./die6 3 3 3 3 3 3 --seed 48191
  • 18 : [6, 6, 6]
  • 8 : [1, 3, 4]
  • 12 : [3, 5, 4]
  • 18 : [6, 6, 6]
  • 8 : [1, 2, 5]
  • 15 : [6, 6, 3]
  • $ ./die6 3 3 3 3 3 3 --seed 122075
  • 11 : [4, 5, 2]
  • 12 : [3, 6, 3]
  • 18 : [6, 6, 6]
  • 12 : [6, 5, 1]
  • 18 : [6, 6, 6]
  • 18 : [6, 6, 6]

But as long as you don’t use the same seed every time, this will be random enough.

  1. As do Perl’s, PHP’s, and JavaScript’s to different degrees.

  2. For that, read about random.SystemRandom.

  3. I’m ignoring boids for the purpose of this example, because boids don’t have to be random.

  4. 43, 154, 247, 973, 881, 626, 480, 552, 355, 163, 379, 198, 390, 539, 350, 432, 267, 115, 051, 652, 505, 414, 033, 306, 801, 376, 580, 911, 304, 513, 629, 318, 584, 665, 545, 269, 938, 257, 648, 835, 317, 902, 217, 334, 584, 413, 909, 528, 269, 154, 609, 168, 019, 007, 875, 343, 741, 396, 296, 801, 920, 114, 486, 480, 902, 661, 414, 318, 443, 276, 980, 300, 066, 728, 104, 984, 095, 451, 588, 176, 077, 132, 969, 843, 762, 134, 621, 790, 396, 391, 341, 285, 205, 627, 619, 600, 513, 106, 646, 376, 648, 615, 994, 236, 675, 486, 537, 480, 241, 964, 350, 295, 935, 168, 662, 363, 909, 047, 948, 347, 692, 313, 978, 301, 377, 820, 785, 712, 419, 054, 474, 332, 844, 529, 183, 172, 973, 242, 310, 888, 265, 081, 321, 626, 469, 451, 077, 707, 812, 282, 829, 444, 775, 022, 680, 488, 057, 820, 028, 764, 659, 399, 164, 766, 265, 200, 900, 561, 495, 800, 344, 054, 353, 690, 389, 862, 894, 061, 792, 872, 011, 120, 833, 614, 808, 447, 482, 913, 547, 328, 367, 277, 879, 565, 648, 307, 846, 909, 116, 945, 866, 230, 169, 702, 401, 260, 240, 187, 028, 746, 650, 033, 445, 774, 570, 315, 431, 292, 996, 025, 187, 780, 790, 119, 375, 902, 863, 171, 084, 149, 642, 473, 378, 986, 267, 503, 308, 961, 374, 905, 766, 340, 905, 289, 572, 290, 016, 038, 000, 571, 630, 875, 191, 373, 979, 555, 047, 468, 154, 333, 253, 474, 991, 046, 248, 132, 504, 516, 341, 796, 551, 470, 575, 481, 459, 200, 859, 472, 614, 836, 213, 875, 557, 116, 864, 445, 789, 750, 886, 277, 996, 487, 304, 308, 450, 484, 223, 420, 629, 266, 518, 556, 024, 339, 339, 190, 844, 368, 921, 018, 424, 844, 677, 042, 727, 664, 601, 852, 914, 925, 277, 280, 922, 697, 538, 426, 770, 257, 333, 928, 954, 401, 205, 465, 895, 610, 347, 658, 855, 386, 633, 902, 546, 289, 962, 132, 643, 282, 425, 748, 035, 786, 233, 580, 608, 154, 696, 546, 932, 563, 833, 327, 670, 769, 899, 439, 774, 888, 526, 687, 278, 527, 451, 002, 963, 059, 146, 963, 875, 715, 425, 735, 534, 475, 979, 734, 463, 100, 678, 367, 393, 327, 402, 149, 930, 968, 778, 296, 741, 391, 514, 599, 602, 374, 213, 629, 898, 720, 611, 431, 410, 402, 147, 238, 998, 090, 962, 818, 915, 890, 645, 693, 934, 483, 330, 994, 169, 632, 295, 877, 995, 848, 993, 366, 747, 014, 871, 763, 494, 805, 549, 996, 163, 051, 541, 225, 403, 465, 297, 007, 721, 146, 231, 355, 704, 081, 493, 098, 663, 065, 733, 677, 191, 172, 853, 987, 095, 748, 167, 816, 256, 084, 212, 823, 380, 168, 625, 334, 586, 431, 254, 034, 670, 806, 135, 273, 543, 270, 714, 478, 876, 861, 861, 983, 320, 777, 280, 644, 806, 691, 125, 713, 197, 262, 581, 763, 151, 313, 596, 429, 547, 763, 576, 367, 837, 019, 349, 835, 178, 462, 144, 294, 960, 757, 190, 918, 054, 625, 114, 143, 666, 384, 189, 433, 852, 576, 452, 289, 347, 652, 454, 631, 535, 740, 468, 786, 228, 945, 885, 654, 608, 562, 058, 042, 468, 987, 372, 436, 921, 445, 092, 315, 377, 698, 407, 168, 198, 376, 538, 237, 748, 614, 196, 207, 041, 548, 106, 379, 365, 123, 192, 817, 999, 006, 621, 766, 467, 167, 113, 471, 632, 715, 481, 795, 877, 005, 382, 694, 393, 400, 403, 061, 700, 457, 691, 135, 349, 187, 874, 888, 923, 429, 349, 340, 145, 170, 571, 716, 181, 125, 795, 888, 889, 277, 495, 426, 977, 149, 914, 549, 623, 916, 394, 014, 822, 985, 025, 331, 651, 511, 431, 278, 802, 009, 056, 808, 456, 506, 818, 877, 266, 609, 831, 636, 883, 884, 905, 621, 822, 262, 933, 986, 548, 645, 669, 080, 672, 191, 704, 740, 408, 891, 349, 835, 685, 662, 428, 063, 231, 198, 520, 436, 826, 329, 415, 290, 752, 972, 798, 343, 429, 446, 509, 992, 206, 368, 781, 367, 154, 091, 702, 655, 772, 727, 391, 329, 424, 277, 529, 349, 082, 600, 585, 884, 766, 523, 150, 957, 417, 077, 831, 910, 016, 168, 475, 685, 658, 673, 192, 860, 882, 070, 179, 760, 307, 269, 849, 987, 354, 836, 042, 371, 734, 660, 257, 694, 347, 235, 506, 301, 744, 118, 874, 141, 292, 438, 958, 141, 549, 100, 609, 752, 216, 882, 230, 887, 611, 431, 996, 472, 330, 842, 380, 137, 110, 927, 449, 483, 557, 815, 037, 586, 849, 644, 585, 749, 917, 772, 869, 926, 744, 218, 369, 621, 137, 675, 101, 083, 278, 543, 794, 081, 749, 094, 091, 043, 084, 096, 774, 144, 708, 436, 324, 279, 476, 892, 056, 200, 427, 227, 961, 638, 669, 149, 805, 489, 831, 121, 244, 676, 399, 931, 955, 371, 484, 012, 886, 360, 748, 706, 479, 568, 669, 048, 574, 782, 855, 217, 054, 740, 113, 945, 929, 622, 177, 502, 575, 565, 811, 067, 452, 201, 448, 981, 991, 968, 635, 965, 361, 551, 681, 273, 982, 740, 760, 138, 899, 638, 820, 318, 776, 303, 668, 762, 730, 157, 584, 640, 042, 798, 880, 691, 862, 640, 268, 612, 686, 180, 883, 874, 939, 573, 818, 125, 022, 279, 689, 930, 267, 446, 255, 773, 959, 542, 469, 831, 637, 863, 000, 171, 279, 227, 151, 406, 034, 129, 902, 181, 570, 659, 650, 532, 600, 775, 823, 677, 398, 182, 129, 087, 394, 449, 859, 182, 749, 999, 007, 223, 592, 423, 334, 567, 850, 671, 186, 568, 839, 186, 747, 704, 960, 016, 277, 540, 625, 331, 440, 619, 019, 129, 983, 789, 914, 712, 515, 365, 200, 336, 057, 993, 508, 601, 678, 807, 687, 568, 562, 377, 857, 095, 255, 541, 304, 902, 927, 192, 220, 184, 172, 502, 357, 124, 449, 911, 870, 210, 642, 694, 565, 061, 384, 919, 373, 474, 324, 503, 966, 267, 799, 038, 402, 386, 781, 686, 809, 962, 015, 879, 090, 586, 549, 423, 504, 699, 190, 743, 519, 551, 043, 722, 544, 515, 740, 967, 829, 084, 336, 025, 938, 225, 780, 730, 880, 273, 855, 261, 551, 972, 044, 075, 620, 326, 780, 624, 448, 803, 490, 998, 232, 161, 231, 687, 794, 715, 613, 405, 793, 249, 545, 509, 528, 052, 518, 010, 123, 087, 258, 778, 974, 115, 817, 048, 245, 588, 971, 438, 596, 754, 408, 081, 313, 438, 375, 502, 988, 726, 739, 523, 375, 296, 641, 615, 501, 406, 091, 607, 983, 229, 239, 827, 240, 614, 783, 252, 892, 479, 716, 519, 936, 989, 519, 187, 808, 681, 221, 191, 641, 747, 710, 902, 480, 633, 491, 091, 704, 827, 441, 228, 281, 186, 632, 445, 907, 145, 787, 138, 351, 234, 842, 261, 380, 074, 621, 914, 004, 818, 152, 386, 666, 043, 133, 344, 875, 067, 903, 582, 838, 283, 562, 688, 083, 236, 575, 482, 068, 479, 639, 546, 383, 819, 532, 174, 522, 502, 682, 372, 441, 363, 275, 765, 875, 609, 119, 783, 653, 298, 312, 066, 708, 217, 149, 316, 773, 564, 340, 379, 289, 724, 393, 986, 744, 139, 891, 855, 416, 612, 295, 739, 356, 668, 612, 658, 271, 234, 696, 438, 377, 122, 838, 998, 040, 199, 739, 078, 061, 443, 675, 415, 671, 078, 463, 404, 673, 702, 403, 777, 653, 478, 173, 367, 084, 844, 734, 702, 056, 866, 636, 158, 138, 003, 692, 253, 382, 209, 909, 466, 469, 591, 930, 161, 626, 097, 920, 508, 742, 175, 670, 306, 505, 139, 542, 860, 750, 806, 159, 835, 357, 541, 032, 147, 095, 084, 278, 461, 056, 701, 367, 739, 794, 932, 024, 202, 998, 707, 731, 017, 692, 582, 046, 210, 702, 212, 514, 120, 429, 322, 530, 431, 789, 616, 267, 047, 776, 115, 123, 597, 935, 404, 147, 084, 870, 985, 465, 426, 502, 772, 057, 300, 900, 333, 847, 905, 334, 250, 604, 119, 503, 030, 001, 704, 002, 887, 892, 941, 404, 603, 345, 869, 926, 367, 501, 355, 094, 942, 750, 552, 591, 581, 639, 980, 523, 190, 679, 610, 784, 993, 580, 896, 683, 299, 297, 681, 262, 442, 314, 008, 657, 033, 421, 868, 094, 551, 740, 506, 448, 829, 039, 207, 316, 711, 307, 695, 131, 892, 296, 593, 509, 018, 623, 094, 810, 557, 519, 560, 305, 240, 787, 163, 809, 219, 164, 433, 754, 514, 863, 301, 000, 915, 916, 985, 856, 242, 176, 563, 624, 771, 328, 981, 678, 548, 246, 297, 376, 249, 530, 251, 360, 363, 412, 768, 366, 456, 175, 077, 031, 977, 457, 534, 912, 806, 433, 176, 539, 995, 994, 343, 308, 118, 470, 147, 158, 712, 816, 149, 394, 421, 276, 614, 228, 262, 909, 950, 055, 746, 981, 053, 206, 610, 001, 560, 295, 784, 656, 616, 193, 252, 269, 412, 026, 831, 159, 508, 949, 671, 513, 845, 195, 883, 217, 147, 982, 748, 879, 261, 851, 417, 819, 979, 034, 417, 285, 598, 607, 727, 220, 866, 677, 680, 426, 090, 308, 754, 823, 803, 345, 446, 566, 305, 619, 241, 308, 374, 452, 754, 668, 143, 015, 487, 710, 877, 728, 011, 086, 004, 325, 892, 262, 259, 413, 968, 285, 283, 497, 045, 571, 062, 757, 701, 421, 761, 565, 262, 725, 153, 407, 407, 625, 405, 149, 931, 989, 494, 459, 106, 414, 660, 534, 305, 378, 576, 709, 862, 520, 049, 864, 880, 961, 144, 869, 258, 603, 473, 714, 363, 659, 194, 013, 962, 706, 366, 851, 389, 299, 692, 869, 491, 805, 172, 556, 818, 508, 298, 824, 954, 954, 815, 796, 063, 169, 517, 658, 741, 420, 159, 798, 754, 273, 428, 026, 723, 452, 481, 263, 569, 157, 307, 213, 153, 739, 781, 041, 627, 653, 715, 078, 598, 504, 154, 797, 287, 663, 122, 946, 711, 348, 158, 529, 418, 816, 432, 825, 044, 466, 692, 781, 137, 474, 494, 898, 385, 064, 375, 787, 507, 376, 496, 345, 148, 625, 306, 383, 391, 555, 145, 690, 087, 891, 955, 315, 994, 462, 944, 493, 235, 248, 817, 599, 907, 119, 135, 755, 933, 382, 121, 706, 191, 477, 185, 054, 936, 632, 211, 157, 222, 920, 331, 148, 502, 487, 563, 303, 118, 018, 805, 685, 073, 569, 841, 580, 518, 118, 710, 778, 653, 953, 571, 296, 014, 372, 940, 865, 270, 407, 021, 924, 383, 167, 290, 323, 231, 567, 912, 289, 419, 486, 240, 594, 039, 074, 452, 321, 678, 019, 381, 871, 219, 092, 155, 460, 768, 444, 573, 578, 559, 513, 613, 304, 242, 206, 151, 356, 457, 513, 937, 270, 939, 009, 707, 237, 827, 101, 245, 853, 837, 678, 338, 161, 023, 397, 586, 854, 894, 230, 696, 091, 540, 249, 987, 907, 453, 461, 311, 923, 963, 852, 950, 754, 758, 058, 205, 625, 956, 600, 817, 743, 007, 191, 746, 812, 655, 955, 021, 747, 670, 922, 460, 866, 747, 744, 520, 875, 607, 859, 062, 334, 750, 627, 098, 328, 593, 480, 067, 789, 456, 169, 602, 494, 392, 813, 763, 495, 657, 599, 847, 485, 773, 553, 990, 957, 557, 313, 200, 809, 040, 830, 036, 446, 492, 219, 409, 934, 096, 948, 730, 547, 494, 301, 216, 165, 686, 750, 735, 749, 555, 882, 340, 303, 989, 874, 672, 975, 455, 060, 957, 736, 921, 559, 195, 480, 815, 514, 035, 915, 707, 129, 930, 057, 027, 117, 286, 252, 843, 197, 413, 312, 307, 617, 886, 797, 506, 784, 260, 195, 436, 760, 305, 990, 340, 708, 481, 464, 607, 278, 955, 495, 487, 742, 140, 753, 570, 621, 217, 198, 252, 192, 978, 869, 786, 916, 734, 625, 618, 430, 175, 454, 903, 864, 111, 585, 429, 504, 569, 920, 905, 636, 741, 539, 030, 968, 041, 471 if bc is correct.

  5. This assumes we are using a similar version of Python.

  6. There is a different issue regarding whether all possible outcomes are achievable.

  1. <- Roman thumb
  2. V&V brawling weights ->