Cool, thanks — this sounds good! I’ll take some time this weekend to identify the specific lines (as you noted, it’s a nested randomizer that gets called quite a bit). Thanks for the catch on the line 15 error for T200s… I’ll run that through Virtual T since neither of my T200s are operational (and they’ll soon be on sale so someone can lovingly bring them back to life).
Cheers, Steve -- Greetings from Steve Baker (he/him/his) “Gravity brings me down…” > On Feb 8, 2024, at 8:08 PM, B 9 <[email protected]> wrote: > > On Tue, Dec 26, 2023 at 4:36 PM Steve Baker <[email protected] > <mailto:[email protected]>> wrote: > >> That was one of the hardest parts about writing that app — I did a lot of >> research about tips and tricks, and have a few nested randomizer routines in >> there to compensate. While I have not done a statistical study with a >> significant sample set, it kicks out dice rolls that are very random, and >> the folks that I play with feel comfortable with its results. The source >> code is available and I’d be happy to highlight the key bits (some upfront >> prep early in the code and most of the randomizer functions are towards the >> back, etc). > > Steve, > > I was curious how nesting the randomizer had affected the quality of the > randomization, so I poked around at the source code for DICEBOX. While I had > a lot of fun trying to weave my way through the tightly crunched code, in the > end I wasn't able to extract just the randomizer. Could you help me grok it? > Once the routine is extracted, I think your RNG might be useful for anyone > else who wants to reuse your work. > > I've already written code that can do a check of RNG uniformity via the χ² > (chi squared) test on a Model T. (See attachment). It rolls a D sided die N > times and returns a probability p that the RNG is selecting every number > equally. I just need your routine at line 10000 which takes variable D > (number of sides) as input and outputs variable R (random integer from 1 to > D, inclusive). > > —b9 > > P.S. On the Tandy 200, DICEBOX needs a line 15 GOTO 100 or it gives an error. > > > --- CUT HERE --- > > 0 GOTO 1000 REM RNG Tester by hackerb9 > 1 DATA 0.000, 0.000, 0.001, 0.004, 0.016, 2.706, 3.841, 5.024, 6.635, 7.879 > 2 DATA 0.010, 0.020, 0.051, 0.103, 0.211, 4.605, 5.991, 7.378, 9.210, 10.597 > 3 DATA 0.072, 0.115, 0.216, 0.352, 0.584, 6.251, 7.815, 9.348, 11.345, 12.838 > 4 DATA 0.207, 0.297, 0.484, 0.711, 1.064, 7.779, 9.488, 11.143, 13.277, 14.860 > 5 DATA 0.412, 0.554, 0.831, 1.145, 1.610, 9.236, 11.070, 12.833, 15.086, > 16.750 > 6 DATA 0.676, 0.872, 1.237, 1.635, 2.204, 10.645, 12.592, 14.449, 16.812, > 18.548 > 7 DATA 0.989, 1.239, 1.690, 2.167, 2.833, 12.017, 14.067, 16.013, 18.475, > 20.278 > 8 DATA 1.344, 1.646, 2.180, 2.733, 3.490, 13.362, 15.507, 17.535, 20.090, > 21.955 > 9 DATA 1.735, 2.088, 2.700, 3.325, 4.168, 14.684, 16.919, 19.023, 21.666, > 23.589 > 10 DATA 2.156, 2.558, 3.247, 3.940, 4.865, 15.987, 18.307, 20.483, 23.209, > 25.188 > 11 DATA 2.603, 3.053, 3.816, 4.575, 5.578, 17.275, 19.675, 21.920, 24.725, > 26.757 > 12 DATA 3.074, 3.571, 4.404, 5.226, 6.304, 18.549, 21.026, 23.337, 26.217, > 28.300 > 13 DATA 3.565, 4.107, 5.009, 5.892, 7.042, 19.812, 22.362, 24.736, 27.688, > 29.819 > 14 DATA 4.075, 4.660, 5.629, 6.571, 7.790, 21.064, 23.685, 26.119, 29.141, > 31.319 > 15 DATA 4.601, 5.229, 6.262, 7.261, 8.547, 22.307, 24.996, 27.488, 30.578, > 32.801 > 16 DATA 5.142, 5.812, 6.908, 7.962, 9.312, 23.542, 26.296, 28.845, 32.000, > 34.267 > 17 DATA 5.697, 6.408, 7.564, 8.672, 10.085, 24.769, 27.587, 30.191, 33.409, > 35.718 > 18 DATA 6.265, 7.015, 8.231, 9.390, 10.865, 25.989, 28.869, 31.526, 34.805, > 37.156 > 19 DATA 6.844, 7.633, 8.907, 10.117, 11.651, 27.204, 30.144, 32.852, 36.191, > 38.582 > 20 DATA 7.434, 8.260, 9.591, 10.851, 12.443, 28.412, 31.410, 34.170, 37.566, > 39.997 > 21 DATA 8.034, 8.897, 10.283, 11.591, 13.240, 29.615, 32.671, 35.479, 38.932, > 41.401 > 22 DATA 8.643, 9.542, 10.982, 12.338, 14.041, 30.813, 33.924, 36.781, 40.289, > 42.796 > 23 DATA 9.260, 10.196, 11.689, 13.091, 14.848, 32.007, 35.172, 38.076, > 41.638, 44.181 > 24 DATA 9.886, 10.856, 12.401, 13.848, 15.659, 33.196, 36.415, 39.364, > 42.980, 45.559 > 25 DATA 10.520, 11.524, 13.120, 14.611, 16.473, 34.382, 37.652, 40.646, > 44.314, 46.928 > 26 DATA 11.160, 12.198, 13.844, 15.379, 17.292, 35.563, 38.885, 41.923, > 45.642, 48.290 > 27 DATA 11.808, 12.879, 14.573, 16.151, 18.114, 36.741, 40.113, 43.195, > 46.963, 49.645 > 28 DATA 12.461, 13.565, 15.308, 16.928, 18.939, 37.916, 41.337, 44.461, > 48.278, 50.993 > 29 DATA 13.121, 14.256, 16.047, 17.708, 19.768, 39.087, 42.557, 45.722, > 49.588, 52.336 > 30 DATA 13.787, 14.953, 16.791, 18.493, 20.599, 40.256, 43.773, 46.979, > 50.892, 53.672 > 40 DATA 20.707, 22.164, 24.433, 26.509, 29.051, 51.805, 55.758, 59.342, > 63.691, 66.766 > 50 DATA 27.991, 29.707, 32.357, 34.764, 37.689, 63.167, 67.505, 71.420, > 76.154, 79.490 > 60 DATA 35.534, 37.485, 40.482, 43.188, 46.459, 74.397, 79.082, 83.298, > 88.379, 91.952 > 70 DATA 43.275, 45.442, 48.758, 51.739, 55.329, 85.527, 90.531, 95.023, > 100.425, 104.215 > 80 DATA 51.172, 53.540, 57.153, 60.391, 64.278, 96.578, 101.879, 106.629, > 112.329, 116.321 > 90 DATA 59.196, 61.754, 65.647, 69.126, 73.291, 107.565, 113.145, 118.136, > 124.116, 128.299 > 100 DATA 67.328, 70.065, 74.222, 77.929, 82.358, 118.498, 124.342, 129.561, > 135.807, 140.169 > 110 REM Calculate p from df and X2 > 120 IF DF<1 THEN DF=1: PRINT "Using df =" DF > 130 IF DF>100 THEN DF=100: PRINT "Using df =" DF > 140 IF DF>30 AND (DF MOD 10) > 0 THEN DF=DF\10: PRINT "Using df =" DF > 150 ' Select a DATA line to read from > 151 IF DF=1 THEN RESTORE 1 > 152 IF DF=2 THEN RESTORE 2 > 153 IF DF=3 THEN RESTORE 3 > 154 IF DF=4 THEN RESTORE 4 > 155 IF DF=5 THEN RESTORE 5 > 156 IF DF=6 THEN RESTORE 6 > 157 IF DF=7 THEN RESTORE 7 > 158 IF DF=8 THEN RESTORE 8 > 159 IF DF=9 THEN RESTORE 9 > 160 IF DF=10 THEN RESTORE 10 > 161 IF DF=11 THEN RESTORE 11 > 162 IF DF=12 THEN RESTORE 12 > 163 IF DF=13 THEN RESTORE 13 > 164 IF DF=14 THEN RESTORE 14 > 165 IF DF=15 THEN RESTORE 15 > 166 IF DF=16 THEN RESTORE 16 > 167 IF DF=17 THEN RESTORE 17 > 168 IF DF=18 THEN RESTORE 18 > 169 IF DF=19 THEN RESTORE 19 > 170 IF DF=20 THEN RESTORE 20 > 171 IF DF=21 THEN RESTORE 21 > 172 IF DF=22 THEN RESTORE 22 > 173 IF DF=23 THEN RESTORE 23 > 174 IF DF=24 THEN RESTORE 24 > 175 IF DF=25 THEN RESTORE 25 > 176 IF DF=26 THEN RESTORE 26 > 177 IF DF=27 THEN RESTORE 27 > 178 IF DF=28 THEN RESTORE 28 > 179 IF DF=29 THEN RESTORE 29 > 180 IF DF=30 THEN RESTORE 30 > 181 IF DF=40 THEN RESTORE 40 > 182 IF DF=50 THEN RESTORE 50 > 183 IF DF=60 THEN RESTORE 60 > 184 IF DF=70 THEN RESTORE 70 > 185 IF DF=80 THEN RESTORE 80 > 186 IF DF=90 THEN RESTORE 90 > 187 IF DF=100 THEN RESTORE 100 > 210 REM p value for columns in data > 220 A(0)=1 > 230 A(1)=.995: A(2)=.990: A(3)=.975 > 240 A(4)=.950: A(5)=.900: A(6)=.100 > 250 A(7)=.050: A(8)=.025: A(9)=.010 > 260 A(10)=.005 > 300 REM X2 is chi square, M is alpha > 310 FOR T=1 TO 10 > 320 READ M > 330 IF X2 > M THEN NEXT > 350 P=A(T-1) > 390 RETURN > 990 REM By hackerb9 February 2024. > 999 ' > 1000 REM Chi Squared statistic to > 1001 REM check for uniformity of RNG. > 1002 ' Note: This does NOT check for > 1003 ' independence. For that, use > 1004 ' autocorrelation, gap, poker > 1005 ' or other "diehard" tests. > 1010 ES$=CHR$(27) 'Screen Esc sequences > 1020 PRINT ES$"U"; ' Turn off labels > 1030 CLS > 1038 ' d is number of histogram bins > 1039 ' or, equivalently, sides of a die. > 1040 D=6 > 1050 DIM X(D) > 1059 ' n is number of times to roll. > 1060 N=100 > 1069 ' is the count expected in a bin > 1070 E=N/D > 1099 ' > 1100 REM Roll dice and show histogram bins. > 1120 PRINT"Rolling a";D;"sided die";N;"times"; > 1130 FOR I=1 TO N > 1140 GOSUB 10000 ' R = random(D) > 1150 X(R)=X(R)+1 > 1160 TT=(R-1)*4: GOSUB 1550 > 1170 PRINT X(R); > 1180 NEXT I > 1190 TT=D*4:GOSUB 1550: PRINT > 1199 ' > 1200 REM Calculate chi square statistic > 1201 ' Chi-Square = sum{(x(i)-E)^2 / E} > 1210 FOR I=1 TO D: IF X(I)<5 THEN PRINT "Results may be inaccurate due to > insufficient trials (n ="N", d ="D")": ELSE NEXT > 1230 X2=0: DF=-1 > 1240 FOR I=1 TO D > 1250 X2 = X2 + ( (X(I) - E)^2 / E) > 1260 IF X(I) > 0 THEN DF=DF+1 > 1270 NEXT I > 1280 PRINT "Chi square is";X2 > 1290 PRINT "Degrees of Freedom is";df > 1299 ' > 1300 REM Set p (percentage points) by > 1301 REM looking up x2 (chi square) > 1302 REM at df (degree of freedom) in > 1303 REM the chisq distribution table. > 1310 GOSUB 110 > 1399 ' > 1400 REM Interpret result > 1410 PRINT "p =" P*100 "%" > 1420 PRINT"This Random Number Generator" > 1430 IF P>0.95 THEN PRINT "is too regular. (BAD)": END > 1440 IF P<0.05 THEN PRINT "is not uniformly distributed. (BAD)": END > 1450 PRINT "seems uniformly distributed." > 1460 END > 1499 ' > 1500 'Move cursor to Row AA and Col BB > 1510 PRINT ES$"Y"CHR$(32+AA)CHR$(32+BB); > 1520 RETURN > 1550 REM Move cursor to position TT > 1560 AA=TT\40+1:BB=TT MOD 40:GOSUB 1500 > 1570 RETURN > 9999 ' > 10000 REM RANDOM NUMBER GENERATOR > 10001 ' Input D, integer > 10002 ' Output R, integer > 10003 ' 1..D, inclusive > 10010 R=INT(D*RND(1))+1 > 10090 RETURN > > > <x2.ba>
