001package squidpony.squidmath;
002
003import java.io.Serializable;
004import java.util.Random;
005
006/**
007 * This makes java.util.Random available for testing purposes.
008 * It is relevant mainly as example code, or if you want to
009 * compare what your results would have been without using a
010 * better RNG. Results might not be apparent in some cases,
011 * although the terrible performance of java.util.Random is
012 * likely to be the first thing a user notices if this is
013 * used heavily (i.e. to generate white noise with one call
014 * to {@link #nextDouble()} per cell).
015 * @author Ben McLean
016 */
017public class JavaRNG implements RandomnessSource, Serializable
018{
019    public Random random;
020
021    /** Creates a new generator seeded using Math.random. */
022    public JavaRNG() { this((long) Math.floor(Math.random() * Long.MAX_VALUE)); }
023
024    public JavaRNG( final long seed ) { this.random = new Random(seed); }
025
026    public JavaRNG( final Random random ) { this.random = random; }
027
028    @Override
029    public int next( int bits ) {
030        return random.nextInt() >>> (32 - bits);
031        // return random.next(bits);
032    }
033
034    @Override
035    public long nextLong() { return random.nextLong(); }
036
037    @Override
038    public JavaRNG copy() { return new JavaRNG(random); }
039
040    public int nextInt() { return random.nextInt(); }
041
042    public int nextInt( final int bound ) { return random.nextInt(bound); }
043    /**
044     * Inclusive lower, exclusive upper.
045     * @param lower the lower bound, inclusive, can be positive or negative
046     * @param upper the upper bound, exclusive, should be positive, must be greater than lower
047     * @return a random int at least equal to lower and less than upper
048     */
049    public int nextInt( final int lower, final int upper ) {
050        if ( upper - lower <= 0 ) throw new IllegalArgumentException("Upper bound must be greater than lower bound");
051        return lower + nextInt(upper - lower);
052    }
053
054    public double nextDouble() { return random.nextDouble(); }
055    public double nextDouble(final double outer) {
056        return nextDouble() * outer;
057    }
058
059    /**
060     * Gets a uniform random float in the range [0.0,1.0)
061     * @return a random float at least equal to 0.0 and less than 1.0
062     */
063    public float nextFloat() { return random.nextFloat(); }
064    /**
065     * Gets a random value, true or false.
066     * @return a random true or false value.
067     */
068    public boolean nextBoolean() { return ( random.nextBoolean()); }
069
070    /**
071     * Given a byte array as a parameter, this will fill the array with random bytes (modifying it
072     * in-place).
073     */
074    public void nextBytes( final byte[] bytes ) { random.nextBytes(bytes); }
075
076    @Override
077    public String toString() {
078        return "JavaRNG wrapping java.util.Random with id " + System.identityHashCode(random);
079    }
080
081    @Override
082    public boolean equals(Object o) {
083        if (this == o) return true;
084        if (o == null || getClass() != o.getClass()) return false;
085
086        JavaRNG javaRNG = (JavaRNG) o;
087
088        return random.equals(javaRNG.random);
089    }
090
091    @Override
092    public int hashCode() {
093        return random.hashCode() * 31;
094    }
095}