Class MoonwalkRNG

java.lang.Object
squidpony.squidmath.AbstractRNG
squidpony.squidmath.MoonwalkRNG
All Implemented Interfaces:
Serializable, IRNG, IStatefulRNG, RandomnessSource, SkippingRandomness, StatefulRandomness

public class MoonwalkRNG
extends AbstractRNG
implements IStatefulRNG, SkippingRandomness, Serializable
An IRNG implementation that allows the extra functionality of a StatefulRandomness and a SkippingRandomness, as well as allowing reverse-lookup of the state that produced a long using the static inverseNextLong(long) method, and distance checks between two generated numbers with the static distance(long, long) method. A task this might be useful for could be simple obfuscation that is hard to undo unless you know the starting state, like this:
  1. take a sequence of numbers or characters and a MoonwalkRNG with a given starting state,
  2. modify each item in the sequence with a random but reversible change such as a bitwise XOR with a number produced by the MoonwalkRNG (such as by nextInt()),
  3. on a later run, take the modified sequence and a MoonwalkRNG with the same starting state (but no direct access to the starting sequence), and skip ahead by the length of the sequence with skip(long),
  4. starting at the end of the sequence, apply the reverse change to the items with numbers generated backwards by MoonwalkRNG with previousInt() (such as a XOR if the number was originally modified with a XOR or an addition if it was originally modified with a subtraction),
  5. when the full sequence has been reversed, you now have the original sequence again.
This is also possible with determine() methods in various RandomnessSource implementations, but those require some extra work to allow them to use sequential inputs instead of inputs that have a large difference between generations.
Internally, this is like StatefulRNG if it always used LightRNG and allowed access to LightRNG's skip() method as well as the reverse lookup and distance methods that aren't in LightRNG but are allowed by it.
The name comes from the ability of this generator to easily go in reverse, like the moonwalk dance move, including previousLong() and skip(long) for advancing backwards, but also inverseNextLong(long) to go from output back to state.
Created by Tommy Ettinger on 4/14/2018.
See Also:
Serialized Form
  • Constructor Details

    • MoonwalkRNG

      public MoonwalkRNG()
      Default constructor; uses a random seed.
    • MoonwalkRNG

      public MoonwalkRNG​(long seed)
      Constructs a MoonwalkRNG with the given seed as-is; any seed can be given.
      Parameters:
      seed - any long
    • MoonwalkRNG

      public MoonwalkRNG​(CharSequence seedString)
      String-seeded constructor; uses a platform-independent hash of the String (it does not use String.hashCode) as a seed for this RNG.
      Parameters:
      seedString - any CharSequence, such as a String or StringBuilder; if null this will use the seed 0
  • Method Details

    • next

      public int next​(int bits)
      Get up to 32 bits (inclusive) of random output; the int this produces will not require more than bits bits to represent.
      Specified by:
      next in interface IRNG
      Specified by:
      next in interface RandomnessSource
      Specified by:
      next in class AbstractRNG
      Parameters:
      bits - an int between 1 and 32, both inclusive
      Returns:
      a random number that fits in the specified number of bits
    • nextInt

      public int nextInt()
      Get a random integer between Integer.MIN_VALUE to Integer.MAX_VALUE (both inclusive).
      Specified by:
      nextInt in interface IRNG
      Specified by:
      nextInt in class AbstractRNG
      Returns:
      a 32-bit random int.
    • nextLong

      public long nextLong()
      Get a random long between Long.MIN_VALUE to Long.MAX_VALUE (both inclusive).
      Specified by:
      nextLong in interface IRNG
      Specified by:
      nextLong in interface RandomnessSource
      Specified by:
      nextLong in class AbstractRNG
      Returns:
      a 64-bit random long.
    • previousInt

      public int previousInt()
      Get a random integer between Integer.MIN_VALUE to Integer.MAX_VALUE (both inclusive), but advances the state "backwards," such that calling nextInt() alternating with this method will return the same pair of numbers for as long as you keep alternating those two calls. This can be useful with skip(long) when it advances ahead by a large amount and you want to step backward to reverse another set of forward-advancing number generations that had been done by other code.
      Returns:
      a 32-bit random int.
    • previousLong

      public long previousLong()
      Get a random long between Long.MIN_VALUE to Long.MAX_VALUE (both inclusive), but advances the state "backwards," such that calling nextLong() alternating with this method will return the same pair of numbers for as long as you keep alternating those two calls. This can be useful with skip(long) when it advances ahead by a large amount and you want to step backward to reverse another set of forward-advancing number generations that had been done by other code.
      Returns:
      a 64-bit random long.
    • nextBoolean

      public boolean nextBoolean()
      Get a random bit of state, interpreted as true or false with approximately equal likelihood.
      This implementation uses a sign check and is able to avoid some calculations needed to get a full int or long.
      Specified by:
      nextBoolean in interface IRNG
      Specified by:
      nextBoolean in class AbstractRNG
      Returns:
      a random boolean.
    • nextDouble

      public double nextDouble()
      Gets a random double between 0.0 inclusive and 1.0 exclusive. This returns a maximum of 0.9999999999999999 because that is the largest double value that is less than 1.0 .
      Specified by:
      nextDouble in interface IRNG
      Specified by:
      nextDouble in class AbstractRNG
      Returns:
      a double between 0.0 (inclusive) and 0.9999999999999999 (inclusive)
    • nextFloat

      public float nextFloat()
      Gets a random float between 0.0f inclusive and 1.0f exclusive. This returns a maximum of 0.99999994 because that is the largest float value that is less than 1.0f .
      Specified by:
      nextFloat in interface IRNG
      Specified by:
      nextFloat in class AbstractRNG
      Returns:
      a float between 0f (inclusive) and 0.99999994f (inclusive)
    • copy

      public MoonwalkRNG copy()
      Creates a copy of this MoonwalkRNG; it will generate the same random numbers, given the same calls in order, as this MoonwalkRNG at the point copy() is called. The copy will not share references with this MoonwalkRNG.
      Specified by:
      copy in interface IRNG
      Specified by:
      copy in interface RandomnessSource
      Specified by:
      copy in interface StatefulRandomness
      Specified by:
      copy in class AbstractRNG
      Returns:
      a copy of this IRNG
    • toSerializable

      Gets a view of this IRNG in a way that implements Serializable, which may simply be this IRNG if it implements Serializable as well as IRNG.
      For implementors: It is suggested to return an RNG initialized by calling RNG(long) with nextLong() if you are unable to save the current state of this IRNG and the caller still needs something saved. This won't preserve the current state or the choice of IRNG implementation, however, so it is simply a last resort in case you don't want to throw an exception.
      Specified by:
      toSerializable in interface IRNG
      Specified by:
      toSerializable in class AbstractRNG
      Returns:
      a Serializable view of this IRNG or a similar one; may be this
    • skip

      public long skip​(long advance)
      Advances or rolls back the SkippingRandomness' state without actually generating each number. Skips forward or backward a number of steps specified by advance, where a step is equal to one call to nextLong(), and returns the random number produced at that step. Negative numbers can be used to step backward, or 0 can be given to get the most-recently-generated long from nextLong().
      Specified by:
      skip in interface SkippingRandomness
      Parameters:
      advance - Number of future generations to skip over; can be negative to backtrack, 0 gets the most-recently-generated number
      Returns:
      the random long generated after skipping forward or backwards by advance numbers
    • getState

      public long getState()
      Get the current internal state of the StatefulRandomness as a long.
      Specified by:
      getState in interface StatefulRandomness
      Returns:
      the current internal state of this object as a long
    • setState

      public void setState​(long state)
      Set the current internal state of this StatefulRandomness with a long; all longs are allowed.
      Specified by:
      setState in interface StatefulRandomness
      Parameters:
      state - a 64-bit long; this can be any long, even 0
    • toString

      public String toString()
      Overrides:
      toString in class Object
    • equals

      public boolean equals​(Object o)
      Overrides:
      equals in class Object
    • hashCode

      public int hashCode()
      Overrides:
      hashCode in class Object
    • inverseNextLong

      public static long inverseNextLong​(long out)
      Given the output of a call to nextLong() as out, this finds the state of the MoonwalkRNG that produce that output. If you set the state of a MoonwalkRNG with setState(long) to the result of this method and then call nextLong() on it, you should get back out.
      This isn't as fast as nextLong(), but both run in constant time. Some random number generators take more than constant time to reverse, so one was chosen for this class that would still be efficient (LightRNG).
      This will not necessarily work if out was produced by a generator other than a MoonwalkRNG, or if it was produced with the bounded AbstractRNG.nextLong(long) method by any generator.
      Parameters:
      out - a long as produced by nextLong(), without changes
      Returns:
      the state of the RNG that will produce the given long
    • distance

      public static long distance​(long out1, long out2)
      Returns the number of steps (where a step is equal to one call to most random number methods in this class) needed to go from receiving out1 from a MoonwalkRNG's nextLong() method to receiving out2 from another call. This number can be used with skip(long) to move a MoonwalkRNG forward or backward by the desired distance.
      Parameters:
      out1 - a long as produced by nextLong(), without changes
      out2 - a long as produced by nextLong(), without changes
      Returns:
      the number of calls to nextLong() that would be required to go from producing out1 to producing out2; can be positive or negative, and can be passed to skip(long)