/* * We don't need crypto-strength randomness here; we just use random(). */ #include #include #include #include #include #include "pline.h" #include "dice.h" /* * Initialize the randomness subsystem. We srandom() with the XOR of a * handful of values we can get quickly and easily, at least some of * which will typically vary from run to run. * * Arguably we should hash these values with at least a CRC, but I * doubt it's worth the bother. */ void initrandom(void) { struct timeval tv; gettimeofday(&tv,(struct timezone *)0); srandom(tv.tv_sec^tv.tv_usec^getpid()^getuid()^gethostid()); } /* * rnd(N) - random number in [0..N). Very simple. */ int rnd(int n) { return(random()%n); } /* * onein(N) - return true 1/N of the time. The only notable thing here * is the test on the argument; it's convenient elsewhere to not have * to special-case arguments less than 2. */ int onein(int n) { return((n>1)?!rnd(n):1); } /* * Roll N dice with S sides (numbered [1..S]) and return the total. * This is internal to roll(), below. */ static int d(int n, int sides) { int total; total = 0; for (;n>0;n--) { total += 1 + (random() % sides); } return(total); } /* * Roll dice. This consists of a sum of simple numbers and dice rolls * (all but the first can actually be negated). For example, this * could roll "4d8" or "2d100+50" or "100d2-50" or "2d8+d10+4d3". * Note in particular that there is no requirement that the side * counts of the dice be physically reasonable ones; it's perfectly * fine to use "d1000" or "d7". */ int roll(const char *str) { int total; int ndice; int nsides; const char *cp; int neg; cp = str; neg = 0; total = 0; while (1) { if (isdigit((unsigned char)*cp)) { ndice = 0; while (isdigit((unsigned char)*cp)) { ndice = (10 * ndice) + (*cp - '0'); cp ++; } } else if (*cp == 'd') { ndice = 1; } if (*cp == 'd') { cp ++; nsides = 0; while (isdigit((unsigned char)*cp)) { nsides = (10 * nsides) + (*cp - '0'); cp ++; } if (neg) { total -= d(ndice,nsides); } else { total += d(ndice,nsides); } } else { if (neg) { total -= ndice; } else { total += ndice; } } neg = 0; if (*cp == '+') { cp ++; } else if (*cp == '-') { neg = 1; cp ++; } else if (*cp == '\0') { break; } else { panic("Bad dice spec `%s' to roll()",str); } } return(total); }