make rank() static again
[NetHack.git] / src / rnd.c
blobbeb4992ed3122f2f9248d99004082ad4bb586af9
1 /* NetHack 3.7 rnd.c $NHDT-Date: 1596498205 2020/08/03 23:43:25 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.30 $ */
2 /* Copyright (c) 2004 by Robert Patrick Rankin */
3 /* NetHack may be freely redistributed. See license for details. */
5 #include "hack.h"
7 #ifdef USE_ISAAC64
8 #include "isaac64.h"
10 staticfn int whichrng(int (*fn)(int));
11 staticfn int RND(int);
12 staticfn void set_random(unsigned long, int (*)(int));
14 #if 0
15 static isaac64_ctx rng_state;
16 #endif
18 struct rnglist_t {
19 int (*fn)(int);
20 boolean init;
21 isaac64_ctx rng_state;
24 enum { CORE = 0, DISP = 1 };
26 static struct rnglist_t rnglist[] = {
27 { rn2, FALSE, { 0 } }, /* CORE */
28 { rn2_on_display_rng, FALSE, { 0 } }, /* DISP */
31 staticfn int
32 whichrng(int (*fn)(int))
34 int i;
36 for (i = 0; i < SIZE(rnglist); ++i)
37 if (rnglist[i].fn == fn)
38 return i;
39 return -1;
42 void
43 init_isaac64(unsigned long seed, int (*fn)(int))
45 unsigned char new_rng_state[sizeof seed];
46 unsigned i;
47 int rngindx = whichrng(fn);
49 if (rngindx < 0)
50 panic("Bad rng function passed to init_isaac64().");
52 for (i = 0; i < sizeof seed; i++) {
53 new_rng_state[i] = (unsigned char) (seed & 0xFF);
54 seed >>= 8;
56 isaac64_init(&rnglist[rngindx].rng_state, new_rng_state,
57 (int) sizeof seed);
60 staticfn int
61 RND(int x)
63 return (isaac64_next_uint64(&rnglist[CORE].rng_state) % x);
66 /* 0 <= rn2(x) < x, but on a different sequence from the "main" rn2;
67 used in cases where the answer doesn't affect gameplay and we don't
68 want to give users easy control over the main RNG sequence. */
69 int
70 rn2_on_display_rng(int x)
72 return (isaac64_next_uint64(&rnglist[DISP].rng_state) % x);
75 #else /* USE_ISAAC64 */
77 /* "Rand()"s definition is determined by [OS]conf.h */
78 #if defined(UNIX) || defined(RANDOM)
79 #define RND(x) ((int) (Rand() % (long) (x)))
80 #else
81 /* Good luck: the bottom order bits are cyclic. */
82 #define RND(x) ((int) ((Rand() >> 3) % (x)))
83 #endif
84 int
85 rn2_on_display_rng(int x)
87 static unsigned seed = 1;
88 seed *= 2739110765;
89 return (int) ((seed >> 16) % (unsigned) x);
91 #endif /* USE_ISAAC64 */
93 /* 0 <= rn2(x) < x */
94 int
95 rn2(int x)
97 #if (NH_DEVEL_STATUS != NH_STATUS_RELEASED)
98 if (x <= 0) {
99 impossible("rn2(%d) attempted", x);
100 return 0;
102 x = RND(x);
103 return x;
104 #else
105 return RND(x);
106 #endif
109 /* 0 <= rnl(x) < x; sometimes subtracting Luck;
110 good luck approaches 0, bad luck approaches (x-1) */
112 rnl(int x)
114 int i, adjustment;
116 #if (NH_DEVEL_STATUS != NH_STATUS_RELEASED)
117 if (x <= 0) {
118 impossible("rnl(%d) attempted", x);
119 return 0;
121 #endif
123 adjustment = Luck;
124 if (x <= 15) {
125 /* for small ranges, use Luck/3 (rounded away from 0);
126 also guard against architecture-specific differences
127 of integer division involving negative values */
128 adjustment = (abs(adjustment) + 1) / 3 * sgn(adjustment);
130 * 11..13 -> 4
131 * 8..10 -> 3
132 * 5.. 7 -> 2
133 * 2.. 4 -> 1
134 * -1,0,1 -> 0 (no adjustment)
135 * -4..-2 -> -1
136 * -7..-5 -> -2
137 * -10..-8 -> -3
138 * -13..-11-> -4
142 i = RND(x);
143 if (adjustment && rn2(37 + abs(adjustment))) {
144 i -= adjustment;
145 if (i < 0)
146 i = 0;
147 else if (i >= x)
148 i = x - 1;
150 return i;
153 /* 1 <= rnd(x) <= x */
155 rnd(int x)
157 #if (NH_DEVEL_STATUS != NH_STATUS_RELEASED)
158 if (x <= 0) {
159 impossible("rnd(%d) attempted", x);
160 return 1;
162 #endif
163 x = RND(x) + 1;
164 return x;
168 rnd_on_display_rng(int x)
170 return rn2_on_display_rng(x) + 1;
173 /* d(N,X) == NdX == dX+dX+...+dX N times; n <= d(n,x) <= (n*x) */
175 d(int n, int x)
177 int tmp = n;
179 #if (NH_DEVEL_STATUS != NH_STATUS_RELEASED)
180 if (x < 0 || n < 0 || (x == 0 && n != 0)) {
181 impossible("d(%d,%d) attempted", n, x);
182 return 1;
184 #endif
185 while (n--)
186 tmp += RND(x);
187 return tmp; /* Alea iacta est. -- J.C. */
190 /* 1 <= rne(x) <= max(u.ulevel/3,5) */
192 rne(int x)
194 int tmp, utmp;
196 utmp = (u.ulevel < 15) ? 5 : u.ulevel / 3;
197 tmp = 1;
198 while (tmp < utmp && !rn2(x))
199 tmp++;
200 return tmp;
202 /* was:
203 * tmp = 1;
204 * while (!rn2(x))
205 * tmp++;
206 * return min(tmp, (u.ulevel < 15) ? 5 : u.ulevel / 3);
207 * which is clearer but less efficient and stands a vanishingly
208 * small chance of overflowing tmp
212 /* rnz: everyone's favorite! */
214 rnz(int i)
216 long x = (long) i;
217 long tmp = 1000L;
219 tmp += rn2(1000);
220 tmp *= rne(4);
221 if (rn2(2)) {
222 x *= tmp;
223 x /= 1000;
224 } else {
225 x *= 1000;
226 x /= tmp;
228 return (int) x;
231 /* Sets the seed for the random number generator */
232 #ifdef USE_ISAAC64
234 staticfn void
235 set_random(unsigned long seed,
236 int (*fn)(int))
238 init_isaac64(seed, fn);
241 #else /* USE_ISAAC64 */
243 /*ARGSUSED*/
244 staticfn void
245 set_random(unsigned long seed,
246 int (*fn)(int) UNUSED)
249 * The types are different enough here that sweeping the different
250 * routine names into one via #defines is even more confusing.
252 # ifdef RANDOM /* srandom() from sys/share/random.c */
253 srandom((unsigned int) seed);
254 # else
255 # if defined(__APPLE__) || defined(BSD) || defined(LINUX) \
256 || defined(ULTRIX) || defined(CYGWIN32) /* system srandom() */
257 # if defined(BSD) && !defined(POSIX_TYPES) && defined(SUNOS4)
258 (void)
259 # endif
260 srandom((int) seed);
261 # else
262 # ifdef UNIX /* system srand48() */
263 srand48((long) seed);
264 # else /* poor quality system routine */
265 srand((int) seed);
266 # endif
267 # endif
268 # endif
270 #endif /* USE_ISAAC64 */
272 /* An appropriate version of this must always be provided in
273 port-specific code somewhere. It returns a number suitable
274 as seed for the random number generator */
275 extern unsigned long sys_random_seed(void);
278 * Initializes the random number generator.
279 * Only call once.
281 void
282 init_random(int (*fn)(int))
284 set_random(sys_random_seed(), fn);
287 /* Reshuffles the random number generator. */
288 void
289 reseed_random(int (*fn)(int))
291 /* only reseed if we are certain that the seed generation is unguessable
292 * by the players. */
293 if (has_strong_rngseed)
294 init_random(fn);
297 /* randomize the given list of numbers 0 <= i < count */
298 void
299 shuffle_int_array(int *indices, int count)
301 int i, iswap, temp;
303 for (i = count - 1; i > 0; i--) {
304 if ((iswap = rn2(i + 1)) == i)
305 continue;
306 temp = indices[i];
307 indices[i] = indices[iswap];
308 indices[iswap] = temp;
312 /*rnd.c*/