*/
-#include "victrix-abyssi.hh"
+#include "rng.hh"
#include <time.h>
#include <unistd.h>
#include <stdint.h>
+#include <arpa/inet.h>
-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
--- /dev/null
+/*! \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 <stdint.h>
+
+#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