001package squidpony.squidmath;
002
003import java.io.Serializable;
004import java.util.Arrays;
005import java.util.Collections;
006import java.util.List;
007import java.util.Random;
008
009/**
010 * A high-quality and very fast RNG that has no apparent visual artifacts here; uses Mark Overton's CMR subcycle
011 * generator type, with a multiplication on the output. This is meant to be an answer to when people ask for a
012 * bare-minimum generator that's still "good enough" for games. It still passes at least 8TB of PractRand testing and
013 * passes TestU01 with both the bits in normal forward order and in reversed bit order, which is remarkable for a
014 * generator this small and simple. It has an unknown period that is fairly high; unless the seed used puts the
015 * generator in a worse cycle (some of which  have a much lower period, like the seed 0), the period probably won't be
016 * exhausted without hours (possibly days) of pure random number generation. It cannot produce all possible longs in its
017 * longest cycle, and it can't produce even a fraction of all possible longs in its smallest cycle.
018 * <br>
019 * This implements RandomnessSource, but if you just want to copy this class with no dependencies, then the class
020 * declaration can easily be changed to {@code public class BasicRandom64 extends Random implements Serializable}
021 * without any other changes. Note, it does extend java.util.Random for additional ease of integration, but doesn't use
022 * the slow {@code synchronized} keyword that Random's implementations do.
023 * <br>
024 * <a href="http://www.drdobbs.com/tools/fast-high-quality-parallel-random-number/231000484">This Dr. Dobb's article has
025 * more on this type of generator</a>. A multiplication applied to the output of a CMR seems to be enough to pass
026 * stringent testing, which is amazing.
027 * @author Mark Overton
028 * @author Tommy Ettinger
029 */
030public class BasicRandom64 extends Random implements RandomnessSource, Serializable {
031    private static final long serialVersionUID = 3L;
032
033    public long state;
034
035    /**
036     * Calls {@link #seed(int)} with a random int value (obtained using {@link Math#random()}).
037     */
038    public BasicRandom64()
039    {
040        seed((int)((Math.random() * 2.0 - 1.0) * 0x80000000));
041    }
042
043    /**
044     * The recommended constructor, this guarantees the generator will have a period of at least 2 to the 20 (roughly
045     * one million, but most if not all initial states will have much longer periods). All ints are permissible values
046     * for the {@code seed} parameter.
047     * @param seed any int; will be used to get the actual state used in the generator (which is a long internally)
048     */
049    public BasicRandom64(final int seed)
050    {
051        seed(seed);
052    }
053
054    /**
055     * Like {@link #BasicRandom64(int)}, this doesn't use the seed as-is, and instead uses it to get a valid state
056     * (which is a long internally). If you want to duplicate the state of another BasicRandom64, get the existing state
057     * either with the field {@link #state} or with {@link #getState()} (you could store the state and load it later
058     * at this stage), then make some new BasicRandom64 (such as with {@code new BasicRandom64(0);}) and call
059     * {@link #setState(long)} with the previous state. You can also use {@link #copy()}.
060     * @param seed any long; will be mixed around and given to {@link #seed(int)} as an int, not used as-is
061     */
062    public BasicRandom64(final long seed)
063    {
064        seed((int)(seed ^ seed >>> 11 ^ seed >>> 21 ^ seed >>> 32));
065    }
066
067    /**
068     * Seeds the state using all bits of the given int {@code s}. Between 33554432 and 4294967296 seeds are possible,
069     * with the actual count probably much closer to 4294967296. This treats the top 25 bits of {@code s} (moved to the
070     * bottom, plus 1, to avoid a seed of 0) as the starting point and then generates the next state at most 127 times,
071     * with each generated state taking less time than {@link #nextLong()}. Some of the starting states are entirely
072     * possible to be within 127 steps of another starting state, so not all seeds are necessarily unique. This is not
073     * guaranteed to put the generator on an optimal subcycle, but it is guaranteed that any subcycle will have a period
074     * of at least 1048575.
075     * @param s all bits are used, none verbatim (0 is tolerated)
076     */
077    public final void seed(final int s) {
078        long v = (s >>> 7) + 1L; // at least 2 to the 25 sequential seeds have periods of at least 1048575.
079        for (int i = (s & 0x7F); i > 0; i--) {
080            v = (v << 29 | v >>> 35) * 0xAC564B05L;
081        }
082        state = v;
083    }
084
085    public long getState() {
086        return state;
087    }
088
089    public void setState(final long seed)
090    {
091        if(seed == 0L) state = 1L;
092        else state = seed;
093    }
094
095    public final long nextLong() {
096        return (state = (state << 29 | state >>> 35) * 0xAC564B05L) * 0x818102004182A025L;
097    }
098
099    /**
100     * Gets an int with at most the specified amount of bits; don't confuse this with {@link #nextInt(int)}, which gets
101     * a number between 0 and its int argument, where this draws from a different (larger) range of random results. For
102     * example, {@code next(2)} can return any 2-bit int,
103     * which is limited to 0, 1, 2, or 3. Note that if you request 0 bits, this can give you any int (32 bits).
104     * @param bits the number of bits to get, from 1 to 32
105     * @return an int with at most the specified bits
106     */
107    public final int next(final int bits) {
108        return (int)((state = (state << 29 | state >>> 35) * 0xAC564B05L) * 0x818102004182A025L) >>> (32 - bits);
109    }
110    public final int nextInt() {
111        return (int)((state = (state << 29 | state >>> 35) * 0xAC564B05L) * 0x818102004182A025L);
112    }
113
114    /**
115     * Returns a random non-negative integer between 0 (inclusive) and the given bound (exclusive),
116     * or 0 if the bound is 0. The bound can be negative, which will produce 0 or a negative result.
117     * <br>
118     * Credit goes to Daniel Lemire, http://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/
119     *
120     * @param bound the outer bound (exclusive), can be negative or positive
121     * @return the found number
122     */
123    public int nextInt(final int bound) {
124        return (int) ((bound * (nextLong() & 0xFFFFFFFFL)) >> 32);
125    }
126    /**
127     * Exclusive on bound (which must be positive), with an inner bound of 0.
128     * If bound is negative or 0 this always returns 0.
129     * <br>
130     * Credit for this method goes to <a href="https://oroboro.com/large-random-in-range/">Rafael Baptista's blog</a>
131     * for the original idea, and the JDK10 Math class' usage of Karatsuba multiplication for the current algorithm. 
132     * This method is drastically faster than the previous implementation when the bound varies often (roughly 4x
133     * faster, possibly more). It also always gets exactly one random long, so by default it advances the state as much
134     * as {@link #nextLong()}.
135     *
136     * @param bound the outer exclusive bound; should be positive, otherwise this always returns 0L
137     * @return a random long between 0 (inclusive) and bound (exclusive)
138     */
139    public long nextLong(long bound) {
140        long rand = nextLong();
141        if (bound <= 0) return 0;
142        final long randLow = rand & 0xFFFFFFFFL;
143        final long boundLow = bound & 0xFFFFFFFFL;
144        rand >>>= 32;
145        bound >>>= 32;
146        final long a = rand * bound;
147        final long b = randLow * boundLow;
148        return (((b >>> 32) + (rand + randLow) * (bound + boundLow) - a - b) >>> 32) + a;
149    }
150
151    /**
152     * Sets the seed using a long, passing its argument to {@link #setState(long)}. That method just sets the public
153     * field {@link #state} to its argument currently, but it may do more to ensure cycle length in the future.
154     * @param seed the initial seed
155     */
156    @Override
157    public void setSeed(long seed) {
158        setState(seed);
159    }
160    /**
161     * Mutates the array arr by switching the contents at pos1 and pos2.
162     * @param arr an array of T; must not be null
163     * @param pos1 an index into arr; must be at least 0 and no greater than arr.length
164     * @param pos2 an index into arr; must be at least 0 and no greater than arr.length
165     */
166    protected static <T> void swap(T[] arr, int pos1, int pos2) {
167        final T tmp = arr[pos1];
168        arr[pos1] = arr[pos2];
169        arr[pos2] = tmp;
170    }
171
172    /**
173     * Shuffle an array using the Fisher-Yates algorithm and returns a shuffled copy, freshly-allocated, without
174     * modifying elements.
175     * <br>
176     * <a href="https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle">Wikipedia has more on this algorithm</a>.
177     *
178     * @param elements an array of T; will not be modified
179     * @return a shuffled copy of elements
180     */
181    public <T> T[] shuffle(T[] elements) {
182        final int size = elements.length;
183        final T[] array = Arrays.copyOf(elements, size);
184        for (int i = size; i > 1; i--) {
185            swap(array, i - 1, nextInt(i));
186        }
187        return array;
188    }
189
190    /**
191     * Shuffles an array in-place using the Fisher-Yates algorithm, affecting indices from 0 (inclusive) to length
192     * (exclusive). May be useful with libGDX Array instances, which can be shuffled with
193     * {@code random.shuffleInPlace(arr.items, arr.size)}. If you don't want the array modified, use
194     * {@link #shuffle(Object[])}.
195     * <br>
196     * <a href="https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle">Wikipedia has more on this algorithm</a>.
197     *
198     * @param elements an array of T; <b>will</b> be modified
199     * @return elements after shuffling it in-place
200     */
201    public <T> T[] shuffleInPlace(T[] elements, int length) {
202        final int size = Math.min(elements.length, length);
203        for (int i = size; i > 1; i--) {
204            swap(elements, i - 1, nextInt(i));
205        }
206        return elements;
207    }
208
209    /**
210     * Shuffles an array in-place using the Fisher-Yates algorithm.
211     * If you don't want the array modified, use {@link #shuffle(Object[])}.
212     * <br>
213     * <a href="https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle">Wikipedia has more on this algorithm</a>.
214     *
215     * @param elements an array of T; <b>will</b> be modified
216     * @return elements after shuffling it in-place
217     */
218    public <T> T[] shuffleInPlace(T[] elements) {
219        final int size = elements.length;
220        for (int i = size; i > 1; i--) {
221            swap(elements, i - 1, nextInt(i));
222        }
223        return elements;
224    }
225    /**
226     * Shuffles a Collection of T items in-place using the Fisher-Yates algorithm.
227     * This only shuffles List data structures.
228     * <br>
229     * <a href="https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle">Wikipedia has more on this algorithm</a>.
230     *
231     * @param elements a List of T; <b>will</b> be modified
232     * @param <T>      can be any non-primitive type.
233     * @return elements after shuffling it in-place
234     */
235    public <T> List<T> shuffleInPlace(List<T> elements) {
236        final int n = elements.size();
237        for (int i = n; i > 1; i--) {
238            Collections.swap(elements, nextInt(i), i - 1);
239        }
240        return elements;
241    }
242
243
244    public BasicRandom64 copy() {
245        BasicRandom64 sr = new BasicRandom64();
246        sr.state = state;
247        return sr;
248    }
249}