Add seedable PRNG using an adaptation the original LCG algorithm.
[open-adventure.git] / misc.c
diff --git a/misc.c b/misc.c
index a08720cbeb20b08cd7414d20eb743343bb3f1d83..320d002a753a6384c768ad5dd42d25809cade628 100644 (file)
--- a/misc.c
+++ b/misc.c
@@ -723,7 +723,7 @@ L2: ATDWRF=I;
 
 
 
-/*  Utility routines (SETBIT, TSTBIT, RAN, RNDVOC, BUG) */
+/*  Utility routines (SETBIT, TSTBIT, set_seed_from_time, get_next_lcg_value, randrange, RNDVOC, BUG) */
 
 #undef SETBIT
 long fSETBIT(long BIT) {
@@ -757,32 +757,32 @@ long TSTBIT;
 
 
 #define TSTBIT(MASK,BIT) fTSTBIT(MASK,BIT)
-#undef RAN
-long fRAN(long RANGE) {
-static long D, R = 0, RAN, T;
-
-/*  Since the ran function in LIB40 seems to be a real lose, we'll use one of
- *  our own.  It's been run through many of the tests in Knuth vol. 2 and
- *  seems to be quite reliable.  RAN returns a value uniformly selected
- *  between 0 and range-1. */
-
-
-       D=1;
-       if(R != 0 && RANGE >= 0) goto L1;
-       DATIME(D,T);
-       R=MOD(T+5,1048576L);
-       D=1000+MOD(D,1000);
-L1:    for (T=1; T<=D; T++) {
-       R=MOD(R*1093L+221587L,1048576L);
-       } /* end loop */
-       RAN=(RANGE*R)/1048576;
-       return(RAN);
+#undef RNDVOC
+
+void set_seed_from_time(void)
+{
+  /* Use the current system time to get seed the ISO rand() function, from which we get a seed for the LCG. */
+  struct timespec ts;
+  clock_gettime(CLOCK_REALTIME, &ts);
+  srand(ts.tv_nsec);
+  lcgstate.x = (unsigned long) rand() % lcgstate.m;
 }
 
+unsigned long get_next_lcg_value(void)
+{
+  /* Return the LCG's current value, and then iterate it. */
+  unsigned long old_x = lcgstate.x;
+  lcgstate.x = (lcgstate.a * lcgstate.x + lcgstate.c) % lcgstate.m;
+  return(old_x);
+}
 
+long randrange(long range)
+{
+  /* Return a random integer from [0, range). */
+  long result = range * get_next_lcg_value() / lcgstate.m;
+  return(result);
+}
 
-#define RAN(RANGE) fRAN(RANGE)
-#undef RNDVOC
 long fRNDVOC(long CHAR, long FORCE) {
 long DIV, I, J, RNDVOC;
 
@@ -795,7 +795,7 @@ long DIV, I, J, RNDVOC;
        RNDVOC=FORCE;
        if(RNDVOC != 0) goto L3;
        for (I=1; I<=5; I++) {
-       J=11+RAN(26);
+       J=11+randrange(26);
        if(I == 2)J=CHAR;
        RNDVOC=RNDVOC*64+J;
        } /* end loop */