From: Martin Read Date: Sat, 8 Feb 2014 17:11:31 +0000 (+0000) Subject: New RNG (Bob Jenkins' small non-crypto PRNG) that actually matches whatever I took... X-Git-Tag: printmsg-purged~14 X-Git-Url: http://git.blackswordsonics.com/?a=commitdiff_plain;h=8b02fc7d2c1cf3bcfec2d3a079c18917c7d24bc2;p=victrix-abyssi New RNG (Bob Jenkins' small non-crypto PRNG) that actually matches whatever I took it from. --- diff --git a/rng.cc b/rng.cc index 1e9fe55..cf5994e 100644 --- a/rng.cc +++ b/rng.cc @@ -27,50 +27,117 @@ */ -#include "victrix-abyssi.hh" +#include "rng.hh" #include #include #include +#include -uint32_t rng_state[5]; -uint32_t saved_state[5]; +Smallprng rng; +void *saved_state_buffer; +int saved_state_size; -uint32_t rng(void) +void Smallprng::extract_serialization(void *data, int size) const { - uint32_t tmp; - tmp = rng_state[0] ^ (rng_state[0] >> 7); - rng_state[0] = rng_state[1]; - rng_state[1] = rng_state[2]; - rng_state[2] = rng_state[3]; - rng_state[3] = rng_state[4]; - rng_state[4] = (rng_state[4] ^ (rng_state[4] << 6)) ^ (tmp ^ (tmp << 13)); - return (rng_state[2] + rng_state[2] + 1) * rng_state[4]; + if (size >= state_size()) + { + uint32_t *foo = (uint32_t *) data; + foo[0] = htonl(a); + foo[1] = htonl(b); + foo[2] = htonl(c); + foo[3] = htonl(d); + } + else + { + // TODO throw a wobbly or at least an exception + } +} + +void Smallprng::inject_serialization(void const *data, int size) +{ + if (size >= state_size()) + { + uint32_t const *foo = (uint32_t const *) data; + a = ntohl(foo[0]); + b = ntohl(foo[1]); + c = ntohl(foo[2]); + d = ntohl(foo[3]); + } + else + { + // TODO throw a wobbly or at least an exception + } } void rng_init(void) { - int i; - /* To make manipulating the RNG by monitoring the system time + /* To make manipulating the Really Nasty God by monitoring the system time * marginally harder, we use PID and UID to perturb the return value of - * time() used to initialise the libc RNG. + * time() used to initialise it. * - * Yes, I am aware that the libc RNG on many platforms is a steaming - * pile of shite. However, I need *something* with which to populate - * my RNG's state array. + * (The currently selected PRNG has an initialization function which + * only takes one input value.) */ - srand(time(NULL) ^ getpid() ^ (getuid() << 16)); - rng_state[0] = rand(); - rng_state[1] = rand(); - rng_state[2] = rand(); - rng_state[3] = rand(); - rng_state[4] = rand(); - /* Flush through the first 100 numbers just in case some bastard - * tries to run us with a 16-bit rand(). */ - for (i = 0; i < 100; i++) + rng.init((uint32_t) (time(NULL) ^ getpid() ^ (getuid() << 16))); + saved_state_size = rng.state_size(); + saved_state_buffer = malloc(saved_state_size); +} + +int exclusive_flat(int lower, int upper) +{ + return lower + one_die(upper - lower - 1); +} + +int inclusive_flat(int lower, int upper) +{ + return lower + zero_die(upper - lower + 1); +} + +Coord inclusive_boxed(Coord topleft, Coord botright) +{ + Coord c = { inclusive_flat(topleft.y, botright.y), inclusive_flat(topleft.x, botright.x) }; + return c; +} + +Coord exclusive_boxed(Coord topleft, Coord botright) +{ + Coord c = { exclusive_flat(topleft.y, botright.y), exclusive_flat(topleft.x, botright.x) }; + return c; +} + +int dice(int count, int sides) +{ + int total = 0; + for ( ; count > 0; count--) + { + total += one_die(sides); + } + return total; +} + +int zero_die(int sides) +{ + int rval; + if (sides < 2) + { + return 0; + } + // This imposes a very slight bias. The more correct approach is + // clumsy to read. + rval = rng() / ((RNG_MAX / sides) + 1); + return rval; +} + +int one_die(int sides) +{ + int rval; + if (sides < 2) { - rng(); + return 1; } + rval = 1 + (rng() / ((RNG_MAX / sides) + 1)); + return rval; } -/* rng.c */ +/* rng.cc */ // vim:cindent diff --git a/rng.hh b/rng.hh new file mode 100644 index 0000000..d46bd5c --- /dev/null +++ b/rng.hh @@ -0,0 +1,98 @@ +/*! \file rng.hh + * \brief RNG-related header for Victrix Abyssi + */ + +/* Copyright 2014 Martin Read + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef RNG_HH +#define RNG_HH + +#include + +#ifndef COORD_HH +#include "coord.hh" +#endif + +#define RNG_MAX 0xFFFFFFFFu +extern void *saved_state_buffer; +extern int saved_state_size; +//extern uint32_t rng(void); +extern void rng_init(void); +extern int zero_die(int sides); /* 0..n-1 */ +extern int one_die(int sides); /* 1..n */ +extern int dice(int count, int sides); +extern int exclusive_flat(int lower, int upper); /* l+1 ... u-1 */ +extern int inclusive_flat(int lower, int upper); /* l ... u */ +extern Coord inclusive_boxed(Coord topleft, Coord botright); +extern Coord exclusive_boxed(Coord topleft, Coord botright); + +/*! \brief An instance of Bob Jenkins' "small noncryptographic PRNG" + * + * See http://burtleburtle.net/bob/rand/smallprng.html for an explanation + * of this generator. + */ +struct Smallprng +{ + uint32_t a; + uint32_t b; + uint32_t c; + uint32_t d; + enum { magic = 0xf1ea5eed }; + void init(uint32_t seed) + { + int i; + a = magic; b = c = d = seed; + for (i = 0; i < 20; ++i) + { + (*this)(); + } + } + static uint32_t rot(uint32_t val, int bits) + { + return (val << bits) | (val >> (32 - bits)); + } + uint32_t operator()(void) + { + uint32_t e = a - rot(b, 27); + a = b ^ rot(c, 17); + b = c + d; + c = d + e; + d = e + a; + return d; + } + static int state_size() + { + return 16; + } + void extract_serialization(void * buf, int size) const; + void inject_serialization(void const * buf, int size); +}; + +extern Smallprng rng; + +#endif + +/* rng.hh */ +// vim:cindent:ts=8:sw=4:expandtab