001package squidpony.squidmath;
002
003import squidpony.StringKit;
004
005import java.io.Serializable;
006
007/**
008 * An IRNG implementation that allows the extra functionality of a StatefulRandomness and a SkippingRandomness, as well
009 * as allowing reverse-lookup of the state that produced a long using the static {@link #inverseNextLong(long)} method,
010 * and distance checks between two generated numbers with the static {@link #distance(long, long)} method. A task this
011 * might be useful for could be simple obfuscation that is hard to undo unless you know the starting state, like this:
012 * <ol>
013 *     <li>take a sequence of numbers or characters and a MoonwalkRNG with a given starting state,</li>
014 *     <li>modify each item in the sequence with a random but reversible change such as a bitwise XOR
015 *     with a number produced by the MoonwalkRNG (such as by {@link #nextInt()}),</li>
016 *     <li>on a later run, take the modified sequence and a MoonwalkRNG with the same starting state (but no direct
017 *     access to the starting sequence), and skip ahead by the length of the sequence with {@link #skip(long)},</li>
018 *     <li>starting at the end of the sequence, apply the reverse change to the items with numbers generated
019 *     <b>backwards</b> by MoonwalkRNG with {@link #previousInt()} (such as a XOR if the number was originally modified
020 *     with a XOR or an addition if it was originally modified with a subtraction),</li>
021 *     <li>when the full sequence has been reversed, you now have the original sequence again.</li>
022 * </ol>
023 * This is also possible with determine() methods in various RandomnessSource implementations, but those require some
024 * extra work to allow them to use sequential inputs instead of inputs that have a large difference between generations.
025 * <br>
026 * Internally, this is like {@link StatefulRNG} if it always used {@link LightRNG} and allowed access to LightRNG's
027 * skip() method as well as the reverse lookup and distance methods that aren't in LightRNG but are allowed by it.
028 * <br>
029 * The name comes from the ability of this generator to easily go in reverse, like the moonwalk dance move, including
030 * {@link #previousLong()} and {@link #skip(long)} for advancing backwards, but also {@link #inverseNextLong(long)} to
031 * go from output back to state.
032 * <br>
033 * Created by Tommy Ettinger on 4/14/2018.
034 */
035public class MoonwalkRNG extends AbstractRNG implements IStatefulRNG, SkippingRandomness, Serializable {
036    private static final long serialVersionUID = 1L;
037
038    private long state;
039    /**
040     * Default constructor; uses a random seed.
041     */
042    public MoonwalkRNG() {
043        this((long) ((Math.random() - 0.5) * 0x10000000000000L)
044                ^ (long) (((Math.random() - 0.5) * 2.0) * 0x8000000000000000L));
045    }
046
047    /**
048     * Constructs a MoonwalkRNG with the given seed as-is; any seed can be given.
049     * @param seed any long
050     */
051    public MoonwalkRNG(long seed) {
052        state = seed;
053    }
054
055    /**
056     * String-seeded constructor; uses a platform-independent hash of the String (it does not use String.hashCode) as a
057     * seed for this RNG.
058     * @param seedString any CharSequence, such as a String or StringBuilder; if null this will use the seed 0
059     */
060    public MoonwalkRNG(CharSequence seedString) {
061        this(CrossHash.hash64(seedString));
062    }
063
064    /**
065     * Get up to 32 bits (inclusive) of random output; the int this produces
066     * will not require more than {@code bits} bits to represent.
067     *
068     * @param bits an int between 1 and 32, both inclusive
069     * @return a random number that fits in the specified number of bits
070     */
071    @Override
072    public int next(int bits) {
073        long z = state += 0x9E3779B97F4A7C15L;
074        z = (z ^ (z >>> 30)) * 0xBF58476D1CE4E5B9L;
075        z = (z ^ (z >>> 27)) * 0x94D049BB133111EBL;
076        return (int)(z ^ (z >>> 31)) >>> (32 - bits);
077    }
078
079    /**
080     * Get a random integer between Integer.MIN_VALUE to Integer.MAX_VALUE (both inclusive).
081     *
082     * @return a 32-bit random int.
083     */
084    @Override
085    public int nextInt() {
086        long z = state += 0x9E3779B97F4A7C15L;
087        z = (z ^ (z >>> 30)) * 0xBF58476D1CE4E5B9L;
088        z = (z ^ (z >>> 27)) * 0x94D049BB133111EBL;
089        return (int)(z ^ (z >>> 31));
090    }
091
092    /**
093     * Get a random long between Long.MIN_VALUE to Long.MAX_VALUE (both inclusive).
094     *
095     * @return a 64-bit random long.
096     */
097    @Override
098    public long nextLong() {
099        long z = state += 0x9E3779B97F4A7C15L;
100        z = (z ^ (z >>> 30)) * 0xBF58476D1CE4E5B9L;
101        z = (z ^ (z >>> 27)) * 0x94D049BB133111EBL;
102        return z ^ (z >>> 31);
103    }
104    /**
105     * Get a random integer between Integer.MIN_VALUE to Integer.MAX_VALUE (both inclusive), but advances the state
106     * "backwards," such that calling {@link #nextInt()} alternating with this method will return the same pair of
107     * numbers for as long as you keep alternating those two calls. This can be useful with {@link #skip(long)} when it
108     * advances ahead by a large amount and you want to step backward to reverse another set of forward-advancing number
109     * generations that had been done by other code.
110     *
111     * @return a 32-bit random int.
112     */
113    public int previousInt() {
114        long z = state -= 0x9E3779B97F4A7C15L;
115        z = (z ^ (z >>> 30)) * 0xBF58476D1CE4E5B9L;
116        z = (z ^ (z >>> 27)) * 0x94D049BB133111EBL;
117        return (int)(z ^ (z >>> 31));
118    }
119
120    /**
121     * Get a random long between Long.MIN_VALUE to Long.MAX_VALUE (both inclusive), but advances the state
122     * "backwards," such that calling {@link #nextLong()} alternating with this method will return the same pair of
123     * numbers for as long as you keep alternating those two calls. This can be useful with {@link #skip(long)} when it
124     * advances ahead by a large amount and you want to step backward to reverse another set of forward-advancing number
125     * generations that had been done by other code.
126     *
127     * @return a 64-bit random long.
128     */
129    public long previousLong() {
130        long z = state -= 0x9E3779B97F4A7C15L;
131        z = (z ^ (z >>> 30)) * 0xBF58476D1CE4E5B9L;
132        z = (z ^ (z >>> 27)) * 0x94D049BB133111EBL;
133        return (z ^ (z >>> 31));
134    }
135
136
137    /**
138     * Get a random bit of state, interpreted as true or false with approximately equal likelihood.
139     * <br>
140     * This implementation uses a sign check and is able to avoid some calculations needed to get a full int or long.
141     *
142     * @return a random boolean.
143     */
144    @Override
145    public boolean nextBoolean() {
146        long z = state += 0x9E3779B97F4A7C15L;
147        z = (z ^ (z >>> 30)) * 0xBF58476D1CE4E5B9L;
148        return ((z ^ (z >>> 27)) * 0x94D049BB133111EBL) < 0;
149    }
150
151    /**
152     * Gets a random double between 0.0 inclusive and 1.0 exclusive.
153     * This returns a maximum of 0.9999999999999999 because that is the largest double value that is less than 1.0 .
154     *
155     * @return a double between 0.0 (inclusive) and 0.9999999999999999 (inclusive)
156     */
157    @Override
158    public double nextDouble() {
159        long z = state += 0x9E3779B97F4A7C15L;
160        z = (z ^ (z >>> 30)) * 0xBF58476D1CE4E5B9L;
161        z = (z ^ (z >>> 27)) * 0x94D049BB133111EBL;
162        return ((z ^ (z >>> 31)) & 0x1fffffffffffffL) * 0x1p-53;
163    }
164
165    /**
166     * Gets a random float between 0.0f inclusive and 1.0f exclusive.
167     * This returns a maximum of 0.99999994 because that is the largest float value that is less than 1.0f .
168     *
169     * @return a float between 0f (inclusive) and 0.99999994f (inclusive)
170     */
171    @Override
172    public float nextFloat() {
173        long z = state += 0x9E3779B97F4A7C15L;
174        z = (z ^ (z >>> 30)) * 0xBF58476D1CE4E5B9L;
175        z = (z ^ (z >>> 27)) * 0x94D049BB133111EBL;
176        return ((z ^ (z >>> 31)) & 0xffffffL) * 0x1p-24f;
177    }
178
179    /**
180     * Creates a copy of this MoonwalkRNG; it will generate the same random numbers, given the same calls in order, as
181     * this MoonwalkRNG at the point copy() is called. The copy will not share references with this MoonwalkRNG.
182     * @return a copy of this IRNG
183     */
184    @Override
185    public MoonwalkRNG copy() {
186        return new MoonwalkRNG(state);
187    }
188
189    /**
190     * Gets a view of this IRNG in a way that implements {@link Serializable}, which may simply be this IRNG if it
191     * implements Serializable as well as IRNG.
192     * <br>
193     * For implementors: It is suggested to return an {@link RNG} initialized by calling
194     * {@link RNG#RNG(long)} with {@link #nextLong()} if you are unable to save the current state of this IRNG and the
195     * caller still needs something saved. This won't preserve the current state or the choice of IRNG implementation,
196     * however, so it is simply a last resort in case you don't want to throw an exception.
197     *
198     * @return a {@link Serializable} view of this IRNG or a similar one; may be {@code this}
199     */
200    @Override
201    public Serializable toSerializable() {
202        return this;
203    }
204
205    /**
206     * Advances or rolls back the SkippingRandomness' state without actually generating each number. Skips forward
207     * or backward a number of steps specified by advance, where a step is equal to one call to {@link #nextLong()},
208     * and returns the random number produced at that step. Negative numbers can be used to step backward, or 0 can be
209     * given to get the most-recently-generated long from {@link #nextLong()}.
210     *
211     * @param advance Number of future generations to skip over; can be negative to backtrack, 0 gets the most-recently-generated number
212     * @return the random long generated after skipping forward or backwards by {@code advance} numbers
213     */
214    @Override
215    public long skip(long advance) {
216        long z = (state += 0x9E3779B97F4A7C15L * advance);
217        z = (z ^ (z >>> 30)) * 0xBF58476D1CE4E5B9L;
218        z = (z ^ (z >>> 27)) * 0x94D049BB133111EBL;
219        return z ^ (z >>> 31);
220    }
221
222    /**
223     * Get the current internal state of the StatefulRandomness as a long.
224     *
225     * @return the current internal state of this object as a long
226     */
227    @Override
228    public long getState() {
229        return state;
230    }
231
232    /**
233     * Set the current internal state of this StatefulRandomness with a long; all longs are allowed.
234     *
235     * @param state a 64-bit long; this can be any long, even 0
236     */
237    @Override
238    public void setState(long state) {
239        this.state = state;
240    }
241
242    @Override
243    public String toString() {
244        return "MoonwalkRNG with state 0x" + StringKit.hex(state) + 'L';
245    }
246
247    @Override
248    public boolean equals(Object o) {
249        if (this == o) return true;
250        if (o == null || getClass() != o.getClass()) return false;
251
252        MoonwalkRNG moonwalkRNG = (MoonwalkRNG) o;
253
254        return state == moonwalkRNG.state;
255    }
256
257    @Override
258    public int hashCode() {
259        return (int) (state ^ (state >>> 32));
260    }
261
262
263    /**
264     * Given the output of a call to {@link #nextLong()} as {@code out}, this finds the state of the MoonwalkRNG that
265     * produce that output. If you set the state of a MoonwalkRNG with {@link #setState(long)} to the result of this
266     * method and then call {@link #nextLong()} on it, you should get back {@code out}.
267     * <br>
268     * This isn't as fast as {@link #nextLong()}, but both run in constant time. Some random number generators take more
269     * than constant time to reverse, so one was chosen for this class that would still be efficient ({@link LightRNG}).
270     * <br>
271     * This will not necessarily work if out was produced by a generator other than a MoonwalkRNG, or if it was produced
272     * with the bounded {@link #nextLong(long)} method by any generator.
273     * @param out a long as produced by {@link #nextLong()}, without changes
274     * @return the state of the RNG that will produce the given long
275     */
276    public static long inverseNextLong(long out)
277    {
278        out ^= out >>> 31;
279        out ^= out >>> 62;
280        out *= 0x319642B2D24D8EC3L;
281        out ^= out >>> 27;
282        out ^= out >>> 54;
283        out *= 0x96DE1B173F119089L;
284        out ^= out >>> 30;
285        return (out ^ out >>> 60) - 0x9E3779B97F4A7C15L;
286        //0x96DE1B173F119089L 0x319642B2D24D8EC3L 0xF1DE83E19937733DL
287    }
288
289    /**
290     * Returns the number of steps (where a step is equal to one call to most random number methods in this class)
291     * needed to go from receiving out1 from a MoonwalkRNG's {@link #nextLong()} method to receiving out2 from another
292     * call. This number can be used with {@link #skip(long)} to move a MoonwalkRNG forward or backward by the desired
293     * distance.
294     * @param out1 a long as produced by {@link #nextLong()}, without changes
295     * @param out2 a long as produced by {@link #nextLong()}, without changes
296     * @return the number of calls to {@link #nextLong()} that would be required to go from producing out1 to producing
297     *         out2; can be positive or negative, and can be passed to {@link #skip(long)}
298     */
299    public static long distance(final long out1, final long out2)
300    {
301        return (inverseNextLong(out2) - inverseNextLong(out1)) * 0xF1DE83E19937733DL;
302    }
303}