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. */
10 staticfn
int whichrng(int (*fn
)(int));
11 staticfn
int RND(int);
12 staticfn
void set_random(unsigned long, int (*)(int));
15 static isaac64_ctx rng_state
;
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 */
32 whichrng(int (*fn
)(int))
36 for (i
= 0; i
< SIZE(rnglist
); ++i
)
37 if (rnglist
[i
].fn
== fn
)
43 init_isaac64(unsigned long seed
, int (*fn
)(int))
45 unsigned char new_rng_state
[sizeof seed
];
47 int rngindx
= whichrng(fn
);
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);
56 isaac64_init(&rnglist
[rngindx
].rng_state
, new_rng_state
,
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. */
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)))
81 /* Good luck: the bottom order bits are cyclic. */
82 #define RND(x) ((int) ((Rand() >> 3) % (x)))
85 rn2_on_display_rng(int x
)
87 static unsigned seed
= 1;
89 return (int) ((seed
>> 16) % (unsigned) x
);
91 #endif /* USE_ISAAC64 */
97 #if (NH_DEVEL_STATUS != NH_STATUS_RELEASED)
99 impossible("rn2(%d) attempted", x
);
109 /* 0 <= rnl(x) < x; sometimes subtracting Luck;
110 good luck approaches 0, bad luck approaches (x-1) */
116 #if (NH_DEVEL_STATUS != NH_STATUS_RELEASED)
118 impossible("rnl(%d) attempted", x
);
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
);
134 * -1,0,1 -> 0 (no adjustment)
143 if (adjustment
&& rn2(37 + abs(adjustment
))) {
153 /* 1 <= rnd(x) <= x */
157 #if (NH_DEVEL_STATUS != NH_STATUS_RELEASED)
159 impossible("rnd(%d) attempted", 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) */
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
);
187 return tmp
; /* Alea iacta est. -- J.C. */
190 /* 1 <= rne(x) <= max(u.ulevel/3,5) */
196 utmp
= (u
.ulevel
< 15) ? 5 : u
.ulevel
/ 3;
198 while (tmp
< utmp
&& !rn2(x
))
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! */
231 /* Sets the seed for the random number generator */
235 set_random(unsigned long seed
,
238 init_isaac64(seed
, fn
);
241 #else /* USE_ISAAC64 */
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
);
255 # if defined(__APPLE__) || defined(BSD) || defined(LINUX) \
256 || defined(ULTRIX) || defined(CYGWIN32) /* system srandom() */
257 # if defined(BSD) && !defined(POSIX_TYPES) && defined(SUNOS4)
262 # ifdef UNIX /* system srand48() */
263 srand48((long) seed
);
264 # else /* poor quality system routine */
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.
282 init_random(int (*fn
)(int))
284 set_random(sys_random_seed(), fn
);
287 /* Reshuffles the random number generator. */
289 reseed_random(int (*fn
)(int))
291 /* only reseed if we are certain that the seed generation is unguessable
293 if (has_strong_rngseed
)
297 /* randomize the given list of numbers 0 <= i < count */
299 shuffle_int_array(int *indices
, int count
)
303 for (i
= count
- 1; i
> 0; i
--) {
304 if ((iswap
= rn2(i
+ 1)) == i
)
307 indices
[i
] = indices
[iswap
];
308 indices
[iswap
] = temp
;