package net.burtleburtle.bob.rand; import net.scapeemulator.util.crypto.StreamCipher; /** * <p>An implementation of the * <a href="http://www.burtleburtle.net/bob/rand/isaacafa.html">ISAAC</a> * psuedorandom number generator.</p> * <pre> * ------------------------------------------------------------------------------ * Rand.java: By Bob Jenkins. My random number generator, ISAAC. * rand.init() -- initialize * rand.val() -- get a random value * MODIFIED: * 960327: Creation (addition of randinit, really) * 970719: use context, not global variables, for internal state * 980224: Translate to Java * ------------------------------------------------------------------------------ * </pre> * <p>This class has been changed to be more conformant to Java and javadoc * conventions.</p> * @author Bob Jenkins */ public final class IsaacRandom implements StreamCipher { /** * The golden ratio. */ private static final int GOLDEN_RATIO = 0x9e3779b9; /** * The log of the size of the result and memory arrays. */ private static final int SIZEL = 8; /** * The size of the result and memory arrays. */ private static final int SIZE = 1 << SIZEL; /** * A mask for pseudorandom lookup. */ private static int MASK = (SIZE - 1) << 2; /** * The count through the results in the results array. */ private int count; /** * The results given to the user. */ private int[] rsl; /** * The internal state. */ private int[] mem; /** * The accumulator. */ private int a; /** * The last result. */ private int b; /** * The counter. */ private int c; /** * Creates the random number generator without an initial seed. */ public IsaacRandom() { mem = new int[SIZE]; rsl = new int[SIZE]; init(false); } /** * Creates the random number generator with the specified seed. * @param seed The seed. */ public IsaacRandom(int[] seed) { mem = new int[SIZE]; rsl = new int[SIZE]; System.arraycopy(seed, 0, rsl, 0, seed.length); init(true); } /** * Generates 256 results. */ private void isaac() { int i, j, x, y; b += ++c; for (i = 0, j = SIZE / 2; i < SIZE / 2;) { x = mem[i]; a ^= a << 13; a += mem[j++]; mem[i] = y = mem[(x & MASK) >> 2] + a + b; rsl[i++] = b = mem[((y >> SIZEL) & MASK) >> 2] + x; x = mem[i]; a ^= a >>> 6; a += mem[j++]; mem[i] = y = mem[(x & MASK) >> 2] + a + b; rsl[i++] = b = mem[((y >> SIZEL) & MASK) >> 2] + x; x = mem[i]; a ^= a << 2; a += mem[j++]; mem[i] = y = mem[(x & MASK) >> 2] + a + b; rsl[i++] = b = mem[((y >> SIZEL) & MASK) >> 2] + x; x = mem[i]; a ^= a >>> 16; a += mem[j++]; mem[i] = y = mem[(x & MASK) >> 2] + a + b; rsl[i++] = b = mem[((y >> SIZEL) & MASK) >> 2] + x; } for (j = 0; j < SIZE / 2;) { x = mem[i]; a ^= a << 13; a += mem[j++]; mem[i] = y = mem[(x & MASK) >> 2] + a + b; rsl[i++] = b = mem[((y >> SIZEL) & MASK) >> 2] + x; x = mem[i]; a ^= a >>> 6; a += mem[j++]; mem[i] = y = mem[(x & MASK) >> 2] + a + b; rsl[i++] = b = mem[((y >> SIZEL) & MASK) >> 2] + x; x = mem[i]; a ^= a << 2; a += mem[j++]; mem[i] = y = mem[(x & MASK) >> 2] + a + b; rsl[i++] = b = mem[((y >> SIZEL) & MASK) >> 2] + x; x = mem[i]; a ^= a >>> 16; a += mem[j++]; mem[i] = y = mem[(x & MASK) >> 2] + a + b; rsl[i++] = b = mem[((y >> SIZEL) & MASK) >> 2] + x; } } /** * Initialises this random number generator. * @param flag Set to {@code true} if a seed was passed to the constructor. */ private void init(boolean flag) { int i; int a, b, c, d, e, f, g, h; a = b = c = d = e = f = g = h = GOLDEN_RATIO; for (i = 0; i < 4; ++i) { a ^= b << 11; d += a; b += c; b ^= c >>> 2; e += b; c += d; c ^= d << 8; f += c; d += e; d ^= e >>> 16; g += d; e += f; e ^= f << 10; h += e; f += g; f ^= g >>> 4; a += f; g += h; g ^= h << 8; b += g; h += a; h ^= a >>> 9; c += h; a += b; } for (i = 0; i < SIZE; i += 8) { /* fill in mem[] with messy stuff */ if (flag) { a += rsl[i]; b += rsl[i + 1]; c += rsl[i + 2]; d += rsl[i + 3]; e += rsl[i + 4]; f += rsl[i + 5]; g += rsl[i + 6]; h += rsl[i + 7]; } a ^= b << 11; d += a; b += c; b ^= c >>> 2; e += b; c += d; c ^= d << 8; f += c; d += e; d ^= e >>> 16; g += d; e += f; e ^= f << 10; h += e; f += g; f ^= g >>> 4; a += f; g += h; g ^= h << 8; b += g; h += a; h ^= a >>> 9; c += h; a += b; mem[i] = a; mem[i + 1] = b; mem[i + 2] = c; mem[i + 3] = d; mem[i + 4] = e; mem[i + 5] = f; mem[i + 6] = g; mem[i + 7] = h; } if (flag) { /* second pass makes all of seed affect all of mem */ for (i = 0; i < SIZE; i += 8) { a += mem[i]; b += mem[i + 1]; c += mem[i + 2]; d += mem[i + 3]; e += mem[i + 4]; f += mem[i + 5]; g += mem[i + 6]; h += mem[i + 7]; a ^= b << 11; d += a; b += c; b ^= c >>> 2; e += b; c += d; c ^= d << 8; f += c; d += e; d ^= e >>> 16; g += d; e += f; e ^= f << 10; h += e; f += g; f ^= g >>> 4; a += f; g += h; g ^= h << 8; b += g; h += a; h ^= a >>> 9; c += h; a += b; mem[i] = a; mem[i + 1] = b; mem[i + 2] = c; mem[i + 3] = d; mem[i + 4] = e; mem[i + 5] = f; mem[i + 6] = g; mem[i + 7] = h; } } isaac(); count = SIZE; } /** * Gets the next random value. * @return The next random value. */ @Override public int nextInt() { if (0 == count--) { isaac(); count = SIZE - 1; } return rsl[count]; } }