1 (*
2  * Hedgewars, a free turn based strategy game
3  * Copyright (c) 2004-2015 Andrey Korotaev <unC0Rr@gmail.com>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; version 2 of the License
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17  *)
18 
19 {$INCLUDE "options.inc"}
20 
21 unit uRandom;
22 (*
23  * This unit supplies platform-independent functions for getting various
24  * pseudo-random values based on a shared seed.
25  *
26  * This is necessary for accomplishing pseudo-random behavior in the game
27  * without causing a desynchronisation of different clients when playing over
28  * a network.
29  *)
30 interface
31 uses uFloat;
32 
33 procedure SetRandomSeed(Seed: shortstring; dropAdditionalPart: boolean); // Sets the seed that should be used for generating pseudo-random values.
GetRandomfnull34 function  GetRandomf: hwFloat; // Returns a pseudo-random hwFloat.
GetRandomnull35 function  GetRandom(m: LongWord): LongWord; inline; // Returns a positive pseudo-random integer smaller than m.
36 procedure AddRandomness(r: LongWord); inline;
rndSignnull37 function  rndSign(num: hwFloat): hwFloat; // Returns num with a random chance of having a inverted sign.
38 
39 
40 implementation
41 
42 var cirbuf: array[0..63] of Longword;
43     n: byte;
44 
45 procedure AddRandomness(r: LongWord); inline;
46 begin
47 n:= (n + 1) and $3F;
48    cirbuf[n]:= cirbuf[n] xor r;
49 end;
50 
GetNextnull51 function GetNext: Longword; inline;
52 begin
53     n:= (n + 1) and $3F;
54     cirbuf[n]:=
55            (cirbuf[(n + 40) and $3F] +           {n - 24 mod 64}
56             cirbuf[(n +  9) and $3F])            {n - 55 mod 64}
57             and $7FFFFFFF;                       {mod 2^31}
58 
59     GetNext:= cirbuf[n];
60 end;
61 
62 procedure SetRandomSeed(Seed: shortstring; dropAdditionalPart: boolean);
63 var i, t, l: Longword;
64 begin
65 n:= 54;
66 
67 if Length(Seed) > 54 then
68     Seed:= copy(Seed, 1, 54); // not 55 to ensure we have odd numbers in cirbuf
69 
70 t:= 0;
71 l:= Length(Seed);
72 
73 while (t < l) and ((not dropAdditionalPart) or (Seed[t + 1] <> '|')) do
74     begin
75     cirbuf[t]:= byte(Seed[t + 1]);
76     inc(t)
77     end;
78 
79 for i:= t to 54 do
80     cirbuf[i]:= $A98765 + 68; // odd number
81 
82 for i:= 0 to 2047 do
83    GetNext;
84 end;
85 
GetRandomfnull86 function GetRandomf: hwFloat;
87 begin
88 GetNext;
89 GetRandomf.isNegative:= false;
90 GetRandomf.QWordValue:= GetNext
91 end;
92 
GetRandomnull93 function GetRandom(m: LongWord): LongWord; inline;
94 begin
95 GetNext;
96 GetRandom:= GetNext mod m
97 end;
98 
rndSignnull99 function rndSign(num: hwFloat): hwFloat;
100 begin
101 num.isNegative:= odd(GetNext);
102 rndSign:= num
103 end;
104 
105 end.
106