001package squidpony.squidmath;
002
003import java.io.Serializable;
004
005/**
006 * An implementation of {@link IRNG} that allows specifying a distribution for all random numbers it produces via a
007 * {@link squidpony.squidmath.IDistribution.SimpleDistribution} value. You can adapt any IDistribution to a
008 * SimpleDistribution with the static methods in SimpleDistribution, like
009 * {@link squidpony.squidmath.IDistribution.SimpleDistribution#fractionalDistribution(IDistribution)}. If no
010 * distribution is specified, this uses {@link CurvedBoundedDistribution#instance}.
011 * <br>
012 * This uses a {@link MoonwalkRNG} internally to handle the number generation that the distribution requests. While you
013 * can call methods on {@link #rng} that are specific to MoonwalkRNG, many distributions will get multiple random
014 * numbers where a normal RNG would only get one, and this makes the state-jumping features of MoonwalkRNG less useful
015 * here. It's still a fast generator when it comes to generating doubles, which is why it's used here; GWT-oriented
016 * generators would be slower at generating doubles on desktop and many mobile platforms.
017 * <br>
018 * Created by Tommy Ettinger on 11/27/2019.
019 */
020public class DistributedRNG extends AbstractRNG implements IStatefulRNG, StatefulRandomness, Serializable {
021
022    private static final long serialVersionUID = 1L;
023    public IDistribution.SimpleDistribution distribution;
024    public MoonwalkRNG rng;
025    
026    public DistributedRNG()
027    {
028        this((long) ((Math.random() - 0.5) * 0x10000000000000L)
029                ^ (long) (((Math.random() - 0.5) * 2.0) * 0x8000000000000000L));
030    }
031    public DistributedRNG(long state)
032    {
033        this(state, CurvedBoundedDistribution.instance);
034    }
035    public DistributedRNG(long state, IDistribution.SimpleDistribution distribution)
036    {
037        this.rng = new MoonwalkRNG(state);
038        this.distribution =  distribution;
039    }
040    /**
041     * Get up to 32 bits (inclusive) of random output; the int this produces
042     * will not require more than {@code bits} bits to represent.
043     *
044     * @param bits an int between 1 and 32, both inclusive
045     * @return a random number that fits in the specified number of bits
046     */
047    @Override
048    public final int next( int bits ) {
049        return (int) (distribution.nextDouble(rng) * (1 << bits));
050    }
051
052    /**
053     * Get a random integer between Integer.MIN_VALUE to Integer.MAX_VALUE (both inclusive).
054     *
055     * @return a 32-bit random int.
056     */
057    @Override
058    public int nextInt() {
059        return (int) (distribution.nextDouble(rng) * 0x1p32 - 0x1p31);
060    }
061
062    /**
063     * Get a random long between Long.MIN_VALUE to Long.MAX_VALUE (both inclusive). This implementation has "holes" in
064     * its range, numbers that it cannot produce regardless of distribution.
065     *
066     * @return a 64-bit random long.
067     */
068    @Override
069    public long nextLong() {
070        return (long) (distribution.nextDouble(rng) * 0x1p64 - 0x1p63);
071    }
072
073    /**
074     * Get a random bit of state, interpreted as true or false with approximately equal likelihood.
075     * 
076     * @return a random boolean.
077     */
078    @Override
079    public boolean nextBoolean() {
080        return distribution.nextDouble(rng) < 0.5;
081    }
082
083    /**
084     * Gets a random double between 0.0 inclusive and 1.0 exclusive.
085     * This returns a maximum of 0.9999999999999999 because that is the largest double value that is less than 1.0 .
086     *
087     * @return a double between 0.0 (inclusive) and 0.9999999999999999 (inclusive)
088     */
089    @Override
090    public double nextDouble() {
091        return distribution.nextDouble(rng);
092    }
093
094    /**
095     * Gets a random float between 0.0f inclusive and 1.0f exclusive.
096     * This returns a maximum of 0.99999994 because that is the largest float value that is less than 1.0f .
097     *
098     * @return a float between 0f (inclusive) and 0.99999994f (inclusive)
099     */
100    @Override
101    public float nextFloat() {
102        return (float) distribution.nextDouble(rng);
103    }
104    /**
105     * Returns a random non-negative integer below the given bound, or 0 if the bound is 0 or
106     * negative.
107     *
108     * @param bound the upper bound (exclusive)
109     * @return the found number
110     */
111    @Override
112    public int nextInt(int bound) {
113        return (int) (distribution.nextDouble(rng) * bound) & ~(bound >> 31);
114    }
115
116    /**
117     * Exclusive on bound (which must be positive), with an inner bound of 0.
118     * If bound is negative or 0 this always returns 0.
119     *
120     * @param bound the outer exclusive bound; should be positive, otherwise this always returns 0L
121     * @return a random long between 0 (inclusive) and bound (exclusive)
122     */
123    @Override
124    public long nextLong(long bound) {
125        return (long) (distribution.nextDouble(rng) * bound) & ~(bound >> 63);
126    }
127
128    /**
129     * Exclusive on bound (which may be positive or negative), with an inner bound of 0.
130     * If bound is negative this returns a negative long; if bound is positive this returns a positive long. The bound
131     * can even be 0, which will cause this to return 0L every time.
132     *
133     * @param bound the outer exclusive bound; can be positive or negative
134     * @return a random long between 0 (inclusive) and bound (exclusive)
135     */
136    @Override
137    public long nextSignedLong(long bound) {
138        return (long) (distribution.nextDouble(rng) * bound);
139    }
140
141    /**
142     * Returns a random non-negative integer between 0 (inclusive) and the given bound (exclusive),
143     * or 0 if the bound is 0. The bound can be negative, which will produce 0 or a negative result.
144     *
145     * @param bound the outer bound (exclusive), can be negative or positive
146     * @return the found number
147     */
148    @Override
149    public int nextSignedInt(int bound) {
150        return (int) (distribution.nextDouble(rng) * bound);
151    }
152    
153    /**
154     * Creates a copy of this IRNG; it will generate the same random numbers, given the same calls in order, as this
155     * IRNG at the point copy() is called. The copy will not share references with this IRNG, except to
156     * {@link #distribution}, which usually shouldn't change much.
157     *
158     * @return a copy of this IRNG
159     */
160    @Override
161    public DistributedRNG copy() {
162        return new DistributedRNG(rng.getState(), distribution);
163    }
164
165    /**
166     * Gets a view of this IRNG in a way that implements {@link Serializable}, which may simply be this IRNG if it
167     * implements Serializable as well as IRNG.
168     *
169     * @return a {@link Serializable} view of this IRNG or a similar one; may be {@code this}
170     */
171    @Override
172    public Serializable toSerializable() {
173        return this;
174    }
175
176    /**
177     * Get the current internal state of the StatefulRandomness as a long.
178     *
179     * @return the current internal state of this object.
180     */
181    @Override
182    public long getState() {
183        return rng.getState();
184    }
185
186    /**
187     * Set the current internal state of this StatefulRandomness with a long; this accepts a state of 0 with no issues.
188     *
189     * @param state a 64-bit long.
190     */
191    @Override
192    public void setState(long state) {
193        rng.setState(state);
194    }
195}