package com.comphenix.xp.extra; import java.util.Random; /** * Represents a random number provider that uses a byte array a source of random numbers. * * @author Kristian */ public class ConstantRandom extends Random { /** * A random number generator that always returns the largest possible value. */ public static ConstantRandom MAXIMUM = new ConstantRandom((byte) 255); /** * A random number generator that always returns the lowest possible value. */ public static ConstantRandom MINIMUM = new ConstantRandom((byte) 0); /** * Generated by Eclipse. */ private static final long serialVersionUID = 2411175741940524236L; private byte[] data; private int index; private boolean wrapAround; /** * Constructs a random generator from a given byte source, starting at the given bit offset. * @param data - source of bytes to use in the random number generator. */ public ConstantRandom(byte[] data) { this.data = data; } /** * Constructs a random generator that uses an infinite stream of bytes as the source of "randomness". * @param wrapValue - the value that will be copied infinitely in the stream. */ public ConstantRandom(byte wrapValue) { this.data = new byte[] { wrapValue }; this.wrapAround = true; } /** * Constructs a random generator from a given byte source, starting at the given bit offset. * @param data - source of bytes to use in the random number generator. * @param wrapAround - TRUE to wrap around when the reader has reached the last byte element, FALSE to raise an exception. */ public ConstantRandom(byte[] data, boolean wrapAround) { this.data = data; this.wrapAround = wrapAround; } /** * Constructs a random generator from a given byte source, starting at the given bit offset. * @param data - source of bytes to use in the random number generator. * @param wrapAround - TRUE to wrap around when the reader has reached the last byte element, FALSE to raise an exception. * @param offset - the bit to start reading from. */ public ConstantRandom(byte[] data, boolean wrapAround, int offset) { this.data = data; this.wrapAround = wrapAround; this.index = offset; } @Override public int nextInt(int n) { // We cannot use the canonical Java method, as it breaks with specific byte arrays. if (n < 0) { throw new IllegalArgumentException("Argument must be positive."); } else { return (int) (nextDouble() * n); } } @Override protected int next(int bits) { // Indexes int byteIndex = index / 8; int bitIndex = index % 8; int written = 0; // Value to return int result = 0; // Increment index already index += bits; // Read as many bits as we're instructed while (bits > 0) { if (byteIndex >= data.length) { if (wrapAround) byteIndex = 0; else throw new ArrayIndexOutOfBoundsException( "Constant random ran out of bytes in array. Use wrap-around."); } // Java + signed byte = me crying int chunk = (data[byteIndex++] & 0xFF) >> bitIndex; int read = 8 - bitIndex; // Remove extra bits if (bits < 8) { chunk &= (1 << bits) - 1; } // Alignment if (bits < read) { read = bits; bitIndex = (bitIndex + read) % 8; } else { bitIndex = 0; } result |= chunk << written; written += read; bits -= read; } return result; } /** * Retrieves the bit array we're using as a source for our random numbers. * @return The bit array, represented with a byte array. */ public byte[] getData() { return data; } /** * Sets the bit array, represented as a byte array, we'll use as a source for our random numbers. * @param data - new byte array to use. */ public void setData(byte[] data) { this.data = data; } /** * Retrieves the bit index in the byte array we're reading from. * @return The current bit index. */ public int getIndex() { return index; } /** * Sets the bit index in the byte array we're reading from. * @param index - new bit index in the array. */ public void setIndex(int index) { this.index = index; } /** * Whether or not we wrap around after reaching the end of the byte array. * @param wrapAround - TRUE to wrap around, FALSE to raise an exception. */ public void setWrapAround(boolean wrapAround) { this.wrapAround = wrapAround; } /** * Whether or not we wrap around after reaching the end of the byte array. * @return TRUE if we wrap around, FALSE otherwise. */ public boolean isWrapAround() { return wrapAround; } }