Prev: 54219 Up: Map Next: 54283
54222: Load A with a pseudo-random number between 0 and the higher of 2 and A (input)
This routine uses a linear congruential generator to generate a new pseudo-random number based upon a seed value. The seed value is stored at 54219, is initially set to the value in the least significant byte of the FRAMES system variable, and subsequently set to the previously generated pseudo-random number. On entering this routine, the A register holds the range for the random number (e.g. 5 means this routine will generate a random number in the range 0-4 inclusive). A range of less than 2 is not allowed, so if A is less than this then it will be set to 2.
The nth pseudo-random number, R(n) is given by:
R(n) = (aR(n - 1) + b) mod c
Where a = 254, b = 253 and c = 65,537.
The instructions between 54235 and 54261 inclusive generate and store the next pseudo-random number based upon the previous one.
The term (aR(n - 1) + b) is calculated as a 24-bit integer by the instructions between 54235 and 54250 inclusive.
The modulo operation is carried out by the instructions between 54252 and 54261 as follows. The divisor, c, has the value 65,537, which can be expressed as:
2562 + 2560
The 24-bit dividend (stored in the registers A, H and L) has the value:
2562A + 2561H + 2560L
This can be expressed as:
2562A + 2561H + 2560A + 2560(L - A)
Since A is an integer, then:
2562A + 2560A
must be an integer multiple of the divisor. We can therefore drop these terms, and those that are left constitute the remainder that we are seeking:
2561H + 2560(L - A)
or:
HL - A
Used by the routines at 38074, 38592, 39601, 41617, 42064, 46317, 46385, 46495, 46577, 47323, 47363, 47431, 51779, 51904, 51924, 52914 and 53083.
Input
A Range
Output
A Generated random number
54222 CP 2 If range is less than 2 then set it to 2
54224 JP NC,54229
54227 LD A,2
54229 LD (54221),A Store range at 54211
54232 PUSH HL Store HL
54233 PUSH DE Store DE
54234 PUSH BC Store BC
54235 LD DE,(54219) Load DE with seed
54239 LD H,E Load least significant byte of random seed into H
54240 LD L,253 Set L to 253
54242 LD A,D Load most significant byte (MSB) of random seed into A
At this point, the three registers A, H and L encode a 24-bit number whose value is (256 × seed + 253)
54243 OR A Reset carry flag
54244 SBC HL,DE Subtract seed from HL and decrement A if carry flag is set
54246 SBC A,0
54248 SBC HL,DE Subtract seed from HL and decrement A if carry flag is set
54250 SBC A,0
At this point, the three registers A, H and L encode a 24-bit number whose value is (254 × seed + 253)
54252 LD E,A Calculate (AHL mod 65,537) loading result into HL, and if this is negative then add one (as zero in HL can represent both zero and 65,536)
54253 LD D,0
54255 SBC HL,DE
54257 JP NC,54261
54260 INC HL
54261 LD (54219),HL Store HL (new seed) at 54219
At this point, HL contains a new pseudo-random 16-bit number
54264 PUSH HL Copy 16-bit pseudo-random number from HL into DE
54265 POP DE
54266 LD A,(54221) Load A with range as stored previously
54269 DEC A Decrease range by 1 to get maximum value as we want the output to range from 0 to (A-1) and load result into B (loop counter)
54270 LD B,A
In the following loop we are obtaining the number of times that 65,536 goes into RANGE × DE. In other words, (RANGE × DE) is divided by 65,536 and the integer part of the result is loaded into A. A is therefore limited to values between zero, and the value A had on entering this routine minus one, inclusive.
54271 XOR A Set A to zero
54272 ADD HL,DE Add DE to HL
54273 JP NC,54277 If DE has not crossed the 65,535 - 0 boundary then skip ahead to 54277
54276 INC A Increase A (count of number of times DE rolls over from 65,535 to 0)
54277 DJNZ 54272 Decrease B and loop back to 54272
54279 POP BC Restore BC
54280 POP DE Restore DE
54281 POP HL Restore HL
54282 RET Return
Prev: 54219 Up: Map Next: 54283