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;
}
}