All Downloads are FREE. Search and download functionalities are using the official Maven repository.

squidpony.squidmath.RNG Maven / Gradle / Ivy

Go to download

SquidLib platform-independent logic and utility code. Please refer to https://github.com/SquidPony/SquidLib .

There is a newer version: 3.0.6
Show newest version
package squidpony.squidmath;

import squidpony.ArrayTools;

import java.io.Serializable;
import java.util.*;

import static squidpony.squidmath.NumberTools.intBitsToFloat;

/**
 * A wrapper class for working with random number generators in a more friendly way.
 * Implements {@link IRNG}, which covers most of the API surface, but RNG implements
 * a decent amount of additional methods. You should consider if your code needs
 * these additional methods, and if not you should use IRNG as the type for when you
 * need some random number generator.
 * 

* Includes methods for getting values between two numbers and for getting * random elements from a collection or array. There are methods to shuffle * a collection and to get a random ordering that can be applied as one shuffle * across multiple collections, such as via {@link OrderedMap#reorder(int...)}, * {@link ArrayTools#reorder(ArrayList, int...)}, and so on. You can construct * an RNG with all sorts of RandomnessSource implementations, and choosing them * is usually not a big concern because the default works very well. If you target * GWT, then it is suggested that you use {@link GWTRNG} instead of RNG; both * implement {@link IRNG}, which is enough for most usage across SquidLib, but * GWTRNG is optimized heavily for better performance on GWT, even returning long * values faster than implementations that natively do their math on longs. It has * worse performance on 64-bit PCs and mobile devices, but should also have better * performance on 32-bit PCs and mobile devices. *
* But if you do want advice on what RandomnessSource to use... {@link DiverRNG} * is the default, and is the fastest generator that passes most tests and can * produce all 64-bit values, and though relative to many of the others it has a * significantly shorter period (the amount of random numbers it will go through * before repeating the sequence), this almost never matters in games, and is * primarily relevant for massively-parallel scientific programs. DiverRNG has a * period of {@code pow(2, 64)} as opposed to {@link XoRoRNG}'s * {@code pow(2, 128) - 1}, or {@link LongPeriodRNG}'s {@code pow(2, 1024) - 1}. * {@link LightRNG} is a solid choice and a former default RandomnessSource; * additional features of LightRNG are exposed in {@link MoonwalkRNG} and using * MoonwalkRNG is recommended if you need unusual features like skipping backwards * in a random number sequence, taking a result of a nextLong() call and reversing * it to get the state that produced it, or calculating the distance in number of * nextLong() calls between two results of nextLong() calls. LightRNG is a * StatefulRandomness, which lets it be used in {@link StatefulRNG}, and so is * DiverRNG, but LightRNG is also a {@link SkippingRandomness}, which means you can * leap forward or backwards in its sequence very efficiently (DiverRNG is not a * SkippingRandomness). {@link ThrustAltRNG} provides similar qualities to LightRNG, * and is one of the fastest generators here, but can't produce all possible 64-bit * values (possibly some 32-bit values as well); it was the default at one point so * you may want to keep compatibility with some versions by specifying ThrustAltRNG. * The defaults have changed in the past as issues are found in various generators; * LightRNG has high quality all-around but is slower than the other defaults, * ThrustAltRNG can't produce all results, LinnormRNG passed tests in an earlier * version of the PractRand test suite but now fails in the current version, and now * the default is DiverRNG, which shares the known issue of LightRNG and LinnormRNG * that it can't produce the same result twice from {@link #nextLong()} until the * generator exhausts its period and repeats its output from the beginning. * For most cases, you should decide between DiverRNG, ThrustAltRNG, LightRNG, * LongPeriodRNG, MiniMover64RNG, and XoshiroStarPhi32RNG based on your priorities. * Some tasks are better solved by using a different class, usually {@link GWTRNG}, * which can always be serialized on GWT to save its state easily and is usually the * fastest substitute for RNG on that platform. DiverRNG is the best if you want high * speed, very good quality of randomness, and expect to generate a reasonable quantity * of numbers for a game (less than 18446744073709551616 numbers) without any single * results being impossible. LightRNG is the second-best at the above criteria, but is * the best option if you need an RNG that can skip backwards or jump forwards without * incurring speed penalties. LongPeriodRNG is best if you for some reason need a massive * amount of random numbers (as in, ten quintillion would be far too little) or want to * split up such a large generator into unrelated subsequences. XoshiroStarPhi32RNG is * best if GWT is a possible target but you either need to generate more than * 18446744073709551616 numbers (but less than 340282366920938463463374607431768211455 * numbers) or you need to ensure that each 128-bit chunk of output is unique; if GWT is * a target but those specific needs don't matter, use GWTRNG. ThrustAltRNG and * MiniMover64RNG are both faster than DiverRNG usually (MiniMover64RNG is the fastest), * but because they are unable to generate some outputs, that may make them a poor choice * for some usage (ThrustAltRNG also has some bias toward specific numbers and produces * them more frequently, but not frequently enough to make it fail statistical tests, and * ThrustAltRNG can skip around in its output sequence like LightRNG). {@link JabRNG} is * a mediocre choice for quality but is tied for the fastest with MiniMover64RNG. *
* There are many more RandomnessSource implementations! You might want significantly less * predictable random results, which {@link IsaacRNG} can provide, along with a * large period. The quality of {@link PermutedRNG} is also good, usually, and it * has a sound basis in PCG-Random, an involved library with many variants on its * RNGs. *
* There may be reasons why you would want a random number generator that uses 32-bit * math instead of the more common 64-bit math, but using a 32-bit int on desktop and * Android won't act the same as that same 32-bit int on GWT. Since GWT is stuck with * JavaScript's implementation of ints with doubles, overflow (which is needed for an * RNG) doesn't work with ints as expected, but does with GWT's implementation of longs. * If targeting GWT, {@link Lathe32RNG} is significantly faster at producing int values * than any long-based generator, and will produce the same results on GWT as on desktop * or Android (not all 32-bit generators do this). {@link Starfish32RNG} goes one step * further than Lathe32RNG at an even distribution, and has better quality, but is * slightly slower. While Lathe32RNG can produce all ints over the course of its period, * it will produce some pairs of ints, or longs, more often than others and will never * produce some longs. Starfish32RNG will produce all longs but one. {@link ThrustAlt32RNG}, * {@link XoshiroStarPhi32RNG}, and {@link Oriole32RNG} are also GWT-safe, but other generators * that were thought to be GWT-friendly are not. These GWT-unsafe generators have other uses, * but should not be used on GWT: {@link PintRNG} and {@link FlapRNG}. All other generators * use longs, and so will be slower than the recommended Starfish32RNG or Lathe32RNG on GWT, * but much faster on 64-bit JREs. * @author Eben Howard - http://squidpony.com - [email protected] * @author Tommy Ettinger * @author smelC */ public class RNG implements Serializable, IRNG { protected RandomnessSource random; protected Random ran = null; private static final long serialVersionUID = 2352426757973945105L; /** * Default constructor; uses {@link DiverRNG}, which is of high quality, but low period (which rarely matters * for games), and has excellent speed, tiny state size, and natively generates 64-bit numbers. *
* Previous versions of SquidLib used different implementations, including {@link LightRNG}, {@link ThrustAltRNG}, * {@link LinnormRNG}, and {@link MersenneTwister}. You can still use one of these by instantiating one of those * classes and passing it to {@link #RNG(RandomnessSource)}, which may be the best way to ensure the same results * across versions. */ public RNG() { this(new DiverRNG()); } /** * Default constructor; uses {@link DiverRNG}, which is of high quality, but low period (which rarely matters * for games), and has excellent speed, tiny state size, and natively generates 64-bit numbers. The seed can be * any long, including 0. * @param seed any long */ public RNG(long seed) { this(new DiverRNG(seed)); } /** * String-seeded constructor; uses a platform-independent hash of the String (it does not use String.hashCode, * instead using {@link CrossHash#hash64(CharSequence)}) as a seed for {@link DiverRNG}, which is of high quality, * but low period (which rarely matters for games), and has excellent speed, tiny state size, and natively generates * 64-bit numbers. */ public RNG(CharSequence seedString) { this(new DiverRNG(CrossHash.hash64(seedString))); } /** * Uses the provided source of randomness for all calculations. This constructor should be used if an alternate * RandomnessSource other than DiverRNG is desirable, such as to keep compatibility with earlier SquidLib * versions that defaulted to MersenneTwister, LightRNG, ThrustAltRNG, or LinnormRNG. *
* If the parameter is null, this is equivalent to using {@link #RNG()} as the constructor. * @param random the source of pseudo-randomness, such as a LightRNG or LongPeriodRNG object */ public RNG(RandomnessSource random) { this.random = (random == null) ? new DiverRNG() : random; } /** * A subclass of java.util.Random that uses a RandomnessSource supplied by the user instead of the default. * * @author Tommy Ettinger */ public static class CustomRandom extends Random { private static final long serialVersionUID = 8211985716129281944L; private final RandomnessSource randomnessSource; /** * Creates a new random number generator. This constructor uses * a DiverRNG with a random seed. */ public CustomRandom() { randomnessSource = new DiverRNG(); } /** * Creates a new random number generator. This constructor uses * the seed of the given RandomnessSource if it has been seeded. * * @param randomnessSource a way to get random bits, supplied by RNG */ public CustomRandom(RandomnessSource randomnessSource) { this.randomnessSource = randomnessSource; } /** * Generates the next pseudorandom number. Subclasses should * override this, as this is used by all other methods. *

*

The general contract of {@code next} is that it returns an * {@code int} value and if the argument {@code bits} is between * {@code 1} and {@code 32} (inclusive), then that many low-order * bits of the returned value will be (approximately) independently * chosen bit values, each of which is (approximately) equally * likely to be {@code 0} or {@code 1}. The method {@code next} is * implemented by class {@code Random} by atomically updating the seed to *

{@code (seed * 0x5DEECE66DL + 0xBL) & ((1L << 48) - 1)}
* and returning *
{@code (int)(seed >>> (48 - bits))}.
* * This is a linear congruential pseudorandom number generator, as * defined by D. H. Lehmer and described by Donald E. Knuth in * The Art of Computer Programming, Volume 3: * Seminumerical Algorithms, section 3.2.1. * * @param bits random bits * @return the next pseudorandom value from this random number * generator's sequence * @since 1.1 */ @Override protected int next(int bits) { return randomnessSource.next(bits); } /** * Returns the next pseudorandom, uniformly distributed {@code long} * value from this random number generator's sequence. The general * contract of {@code nextLong} is that one {@code long} value is * pseudorandomly generated and returned. * * @return the next pseudorandom, uniformly distributed {@code long} * value from this random number generator's sequence */ @Override public long nextLong() { return randomnessSource.nextLong(); } } /** * @return a Random instance that can be used for legacy compatibility */ public Random asRandom() { if (ran == null) { ran = new CustomRandom(random); } return ran; } /** * Returns a value from an even distribution from min (inclusive) to max * (exclusive). * * @param min the minimum bound on the return value (inclusive) * @param max the maximum bound on the return value (exclusive) * @return the found value */ @Override public double between(double min, double max) { return min + (max - min) * nextDouble(); } /** * Returns a value between min (inclusive) and max (exclusive). *
* The inclusive and exclusive behavior is to match the behavior of the similar * method that deals with floating point values. *
* If {@code min} and {@code max} happen to be the same, {@code min} is returned * (breaking the exclusive behavior, but it's convenient to do so). * * @param min the minimum bound on the return value (inclusive) * @param max the maximum bound on the return value (exclusive) * @return the found value */ @Override public int between(int min, int max) { return nextInt(max - min) + min; } /** * Returns a value between min (inclusive) and max (exclusive). *

* The inclusive and exclusive behavior is to match the behavior of the * similar method that deals with floating point values. * * @param min the minimum bound on the return value (inclusive) * @param max the maximum bound on the return value (exclusive) * @return the found value */ @Override public long between(long min, long max) { return nextLong(max - min) + min; } /** * Returns the average of a number of randomly selected numbers from the * provided range, with min being inclusive and max being exclusive. It will * sample the number of times passed in as the third parameter. *

* The inclusive and exclusive behavior is to match the behavior of the * similar method that deals with floating point values. *

* This can be used to weight RNG calls to the average between min and max. * * @param min the minimum bound on the return value (inclusive) * @param max the maximum bound on the return value (exclusive) * @param samples the number of samples to take * @return the found value */ public int betweenWeighted(int min, int max, int samples) { int sum = 0; for (int i = 0; i < samples; i++) { sum += between(min, max); } return Math.round((float) sum / samples); } /** * Returns a random element from the provided array and maintains object * type. * * @param the type of the returned object * @param array the array to get an element from * @return the randomly selected element */ @Override public T getRandomElement(T[] array) { if (array.length < 1) { return null; } return array[nextInt(array.length)]; } /** * Returns a random element from the provided list. If the list is empty * then null is returned. * * @param the type of the returned object * @param list the list to get an element from * @return the randomly selected element */ @Override public T getRandomElement(List list) { if (list.isEmpty()) { return null; } return list.get(nextInt(list.size())); } /** * Returns a random element from the provided ShortSet. If the set is empty * then an exception is thrown. *

*

* Requires iterating through a random amount of the elements in set, so performance depends on the size of set but * is likely to be decent. This is mostly meant for internal use, the same as ShortSet. *

* * @param set the ShortSet to get an element from * @return the randomly selected element */ public short getRandomElement(ShortSet set) { if (set.size <= 0) { throw new UnsupportedOperationException("ShortSet cannot be empty when getting a random element"); } int n = nextInt(set.size); short s = 0; ShortSet.ShortSetIterator ssi = set.iterator(); while (n-- >= 0 && ssi.hasNext) s = ssi.next(); ssi.reset(); return s; } /** * Returns a random element from the provided Collection, which should have predictable iteration order if you want * predictable behavior for identical RNG seeds, though it will get a random element just fine for any Collection * (just not predictably in all cases). If you give this a Set, it should be a LinkedHashSet or some form of sorted * Set like TreeSet if you want predictable results. Any List or Queue should be fine. Map does not implement * Collection, thank you very much Java library designers, so you can't actually pass a Map to this, though you can * pass the keys or values. If coll is empty, returns null. *

*

* Requires iterating through a random amount of coll's elements, so performance depends on the size of coll but is * likely to be decent, as long as iteration isn't unusually slow. This replaces {@code getRandomElement(Queue)}, * since Queue implements Collection and the older Queue-using implementation was probably less efficient. *

* * @param the type of the returned object * @param coll the Collection to get an element from; remember, Map does not implement Collection * @return the randomly selected element */ @Override public T getRandomElement(Collection coll) { int n; if ((n = coll.size()) <= 0) { return null; } n = nextInt(n); T t = null; Iterator it = coll.iterator(); while (n-- >= 0 && it.hasNext()) t = it.next(); return t; } /* * Returns a random elements from the provided queue. If the queue is empty * then null is returned. * *

* Requires iterating through a random amount of the elements in set, so * performance depends on the size of set but is likely to be decent. This * is mostly meant for internal use, the same as ShortSet. *

* * @param the type of the returned object * @param list the list to get an element from * @return the randomly selected element */ /* public T getRandomElement(Queue list) { if (list.isEmpty()) { return null; } return new ArrayList<>(list).get(nextInt(list.size())); }*/ /** * Given a {@link List} l, this selects a random element of l to be the first value in the returned list l2. It * retains the order of elements in l after that random element and makes them follow the first element in l2, and * loops around to use elements from the start of l after it has placed the last element of l into l2. *
* Essentially, it does what it says on the tin. It randomly rotates the List l. *
* If you only need to iterate through a collection starting at a random point, the method getRandomStartIterable() * should have better performance. This was GWT incompatible before GWT 2.8.0 became the version SquidLib uses; now * this method works fine with GWT. * * @param l A {@link List} that will not be modified by this method. All elements of this parameter will be * shared with the returned List. * @param No restrictions on type. Changes to elements of the returned List will be reflected in the parameter. * @return A shallow copy of {@code l} that has been rotated so its first element has been randomly chosen * from all possible elements but order is retained. Will "loop around" to contain element 0 of l after the last * element of l, then element 1, etc. */ public List randomRotation(final List l) { final int sz = l.size(); if (sz == 0) return new ArrayList<>(0); /* * Collections.rotate should prefer the best-performing way to rotate l, * which would be an in-place modification for ArrayLists and an append * to a sublist for Lists that don't support efficient random access. */ List l2 = new ArrayList<>(l); Collections.rotate(l2, nextInt(sz)); return l2; } /** * Get an Iterable that starts at a random location in list and continues on through list in its current order. * Loops around to the beginning after it gets to the end, stops when it returns to the starting location. *
* You should not modify {@code list} while you use the returned reference. And there'll be no * ConcurrentModificationException to detect such erroneous uses. * * @param list A list with a constant-time {@link List#get(int)} method (otherwise performance degrades). * @return An {@link Iterable} that iterates over {@code list} but start at * a random index. If the chosen index is {@code i}, the iterator * will return: * {@code list[i]; list[i+1]; ...; list[list.length() - 1]; list[0]; list[i-1]} */ public Iterable getRandomStartIterable(final List list) { final int sz = list.size(); if (sz == 0) return new ArrayList<>(0); /* * Here's a tricky bit: Defining 'start' here means that every Iterator * returned by the returned Iterable will have the same iteration order. * In other words, if you use more than once the returned Iterable, * you'll will see elements in the same order every time, which is * desirable. */ final int start = nextInt(sz); return new Iterable() { @Override public Iterator iterator() { return new Iterator() { int next = -1; @Override public boolean hasNext() { return next != start; } @Override public T next() { if (next == start) throw new NoSuchElementException("Iteration terminated; check hasNext() before next()"); if (next == -1) /* First call */ next = start; final T result = list.get(next); if (next == sz - 1) /* * Reached the list's end, let's continue from the list's * left. */ next = 0; else next++; return result; } @Override public void remove() { throw new UnsupportedOperationException("Remove is not supported from a randomStartIterable"); } @Override public String toString() { return "RandomStartIterator at index " + next; } }; } }; } /** * Mutates the array arr by switching the contents at pos1 and pos2. * @param arr an array of T; must not be null * @param pos1 an index into arr; must be at least 0 and no greater than arr.length * @param pos2 an index into arr; must be at least 0 and no greater than arr.length */ private static void swap(T[] arr, int pos1, int pos2) { final T tmp = arr[pos1]; arr[pos1] = arr[pos2]; arr[pos2] = tmp; } /** * Shuffle an array using the Fisher-Yates algorithm and returns a shuffled copy. * GWT-compatible since GWT 2.8.0, which is the default if you use libGDX 1.9.5 or higher. *
* Wikipedia has more on this algorithm. * * @param elements an array of T; will not be modified * @param can be any non-primitive type. * @return a shuffled copy of elements */ @Override public T[] shuffle(final T[] elements) { final int size = elements.length; final T[] array = Arrays.copyOf(elements, size); for (int i = size; i > 1; i--) { swap(array, i - 1, nextIntHasty(i)); } return array; } /** * Shuffles an array in-place using the Fisher-Yates algorithm. * If you don't want the array modified, use {@link #shuffle(Object[], Object[])}. *
* Wikipedia has more on this algorithm. * * @param elements an array of T; will be modified * @param can be any non-primitive type. * @return elements after shuffling it in-place */ @Override public T[] shuffleInPlace(T[] elements) { final int size = elements.length; for (int i = size; i > 1; i--) { swap(elements, i - 1, nextIntHasty(i)); } return elements; } /** * Shuffle an array using the Fisher-Yates algorithm. If possible, create a new array or reuse an existing array * with the same length as elements and pass it in as dest; the dest array will contain the shuffled contents of * elements and will also be returned as-is. *
* Wikipedia has more on this algorithm. * * @param elements an array of T; will not be modified * @param can be any non-primitive type. * @param dest Where to put the shuffle. If it does not have the same length as {@code elements}, this will use the * randomPortion method of this class to fill the smaller dest. * @return {@code dest} after modifications */ @Override public T[] shuffle(T[] elements, T[] dest) { if (dest.length != elements.length) return randomPortion(elements, dest); System.arraycopy(elements, 0, dest, 0, elements.length); shuffleInPlace(dest); return dest; } /** * Shuffles a {@link Collection} of T using the Fisher-Yates algorithm and returns an ArrayList of T. *
* Wikipedia has more on this algorithm. * @param elements a Collection of T; will not be modified * @param can be any non-primitive type. * @return a shuffled ArrayList containing the whole of elements in pseudo-random order. */ @Override public ArrayList shuffle(Collection elements) { return shuffle(elements, null); } /** * Shuffles a {@link Collection} of T using the Fisher-Yates algorithm. The result * is allocated if {@code buf} is null or if {@code buf} isn't empty, * otherwise {@code elements} is poured into {@code buf}. *
* Wikipedia has more on this algorithm. * @param elements a Collection of T; will not be modified * @param can be any non-primitive type. * @param buf a buffer as an ArrayList that will be filled with the shuffled contents of elements; * if null or non-empty, a new ArrayList will be allocated and returned * @return a shuffled ArrayList containing the whole of elements in pseudo-random order. */ @Override public ArrayList shuffle(Collection elements, /*@Nullable*/ ArrayList buf) { final ArrayList al; if (buf == null || !buf.isEmpty()) al = new ArrayList<>(elements); else { al = buf; al.addAll(elements); } final int n = al.size(); for (int i = n; i > 1; i--) { Collections.swap(al, nextInt(i), i - 1); } return al; } /** * Shuffles a Collection of T items in-place using the Fisher-Yates algorithm. * This only shuffles List data structures. * If you don't want the array modified, use {@link #shuffle(Collection)}, which returns a List as well. *
* Wikipedia has more on this algorithm. * * @param elements a Collection of T; will be modified * @param can be any non-primitive type. * @return elements after shuffling it in-place */ @Override public List shuffleInPlace(List elements) { final int n = elements.size(); for (int i = n; i > 1; i--) { Collections.swap(elements, nextInt(i), i - 1); } return elements; } /** * Generates a random permutation of the range from 0 (inclusive) to length (exclusive). * Useful for passing to OrderedMap or OrderedSet's reorder() methods. * * @param length the size of the ordering to produce * @return a random ordering containing all ints from 0 to length (exclusive) */ @Override public int[] randomOrdering(int length) { if (length <= 0) return new int[0]; return randomOrdering(length, new int[length]); } /** * Generates a random permutation of the range from 0 (inclusive) to length (exclusive) and stores it in * the dest parameter, avoiding allocations. * Useful for passing to OrderedMap or OrderedSet's reorder() methods. * * @param length the size of the ordering to produce * @param dest the destination array; will be modified * @return dest, filled with a random ordering containing all ints from 0 to length (exclusive) */ @Override public int[] randomOrdering(int length, int[] dest) { if (dest == null) return null; final int n = Math.min(length, dest.length); for (int i = 0; i < n; i++) { dest[i] = i; } for (int i = n - 1; i > 0; i--) { final int r = nextIntHasty(i+1), t = dest[r]; dest[r] = dest[i]; dest[i] = t; } return dest; } /** * Gets a random portion of a Collection and returns it as a new List. Will only use a given position in the given * Collection at most once; does this by shuffling a copy of the Collection and getting a section of it. * * @param data a Collection of T; will not be modified. * @param count the non-negative number of elements to randomly take from data * @param can be any non-primitive type * @return a List of T that has length equal to the smaller of count or data.length */ public List randomPortion(Collection data, int count) { return shuffle(data).subList(0, Math.min(count, data.size())); } /** * Gets a random subrange of the non-negative ints from start (inclusive) to end (exclusive), using count elements. * May return an empty array if the parameters are invalid (end is less than/equal to start, or start is negative). * * @param start the start of the range of numbers to potentially use (inclusive) * @param end the end of the range of numbers to potentially use (exclusive) * @param count the total number of elements to use; will be less if the range is smaller than count * @return an int array that contains at most one of each number in the range */ public int[] randomRange(int start, int end, int count) { if (end <= start || start < 0) return new int[0]; int n = end - start; final int[] data = new int[n]; for (int e = start, i = 0; e < end; e++) { data[i++] = e; } for (int i = 0; i < n - 1; i++) { final int r = i + nextInt(n - i), t = data[r]; data[r] = data[i]; data[i] = t; } final int[] array = new int[Math.min(count, n)]; System.arraycopy(data, 0, array, 0, Math.min(count, n)); return array; } /** * Generates a random float with a curved distribution that centers on 0 (where it has a bias) and can (rarely) * approach -1f and 1f, but not go beyond those bounds. This is similar to {@link Random#nextGaussian()} in that it * uses a curved distribution, but it is not the same. The distribution for the values is similar to Irwin-Hall, and * is frequently near 0 but not too-rarely near -1f or 1f. It cannot produce values greater than or equal to 1f, or * less than -1f, but it can produce -1f. * @return a deterministic float between -1f (inclusive) and 1f (exclusive), that is very likely to be close to 0f */ public float nextCurvedFloat() { final long start = random.nextLong(); return (intBitsToFloat((int)start >>> 9 | 0x3F000000) + intBitsToFloat((int) (start >>> 41) | 0x3F000000) + intBitsToFloat(((int)(start ^ ~start >>> 20) & 0x007FFFFF) | 0x3F000000) + intBitsToFloat(((int) (~start ^ start >>> 30) & 0x007FFFFF) | 0x3F000000) - 3f); } /** * 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 . * * @return a double between 0.0 (inclusive) and 0.9999999999999999 (inclusive) */ @Override public double nextDouble() { return (random.nextLong() & 0x1fffffffffffffL) * 0x1p-53; //this is here for a record of another possibility; it can't generate quite a lot of possible values though //return Double.longBitsToDouble(0x3FF0000000000000L | random.nextLong() >>> 12) - 1.0; } /** * This returns a random double between 0.0 (inclusive) and outer (exclusive). The value for outer can be positive * or negative. Because of how math on doubles works, there are at most 2 to the 53 values this can return for any * given outer bound, and very large values for outer will not necessarily produce all numbers you might expect. * * @param outer the outer exclusive bound as a double; can be negative or positive * @return a double between 0.0 (inclusive) and outer (exclusive) */ @Override public double nextDouble(final double outer) { return (random.nextLong() & 0x1fffffffffffffL) * 0x1p-53 * outer; } /** * 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 . * * @return a float between 0f (inclusive) and 0.99999994f (inclusive) */ @Override public float nextFloat() { return random.next(24) * 0x1p-24f; } /** * This returns a random float between 0.0f (inclusive) and outer (exclusive). The value for outer can be positive * or negative. Because of how math on floats works, there are at most 2 to the 24 values this can return for any * given outer bound, and very large values for outer will not necessarily produce all numbers you might expect. * * @param outer the outer exclusive bound as a float; can be negative or positive * @return a float between 0f (inclusive) and outer (exclusive) */ @Override public float nextFloat(final float outer) { return random.next(24) * 0x1p-24f * outer; } /** * Get a random bit of state, interpreted as true or false with approximately equal likelihood. * This may have better behavior than {@code rng.next(1)}, depending on the RandomnessSource implementation; the * default DiverRNG will behave fine, as will LightRNG and ThrustAltRNG (these all use similar algorithms), but * the normally-high-quality XoRoRNG will produce very predictable output with {@code rng.next(1)} and very good * output with {@code rng.nextBoolean()}. This is a known and considered flaw of Xoroshiro128+, the algorithm used * by XoRoRNG, and a large number of generators have lower quality on the least-significant bit than the most- * significant bit, where this method only checks the most-significant bit. * @return a random boolean. */ @Override public boolean nextBoolean() { return nextLong() < 0L; } /** * Get a random long between Long.MIN_VALUE to Long.MAX_VALUE (both inclusive). * * @return a 64-bit random long. */ @Override public long nextLong() { return random.nextLong(); } /** * Exclusive on bound (which must be positive), with an inner bound of 0. * If bound is negative or 0 this always returns 0. *
* Credit for this method goes to Rafael Baptista's blog, * with some adaptation for signed long values and a 64-bit generator. This method is drastically faster than the * previous implementation when the bound varies often (roughly 4x faster, possibly more). It also always gets * exactly one random number, so it advances the state as much as {@link #nextInt(int)}. * @param bound the outer exclusive bound; should be positive, otherwise this always returns 0L * @return a random long between 0 (inclusive) and bound (exclusive) */ public long nextLong(long bound) { long rand = random.nextLong(); if (bound <= 0) return 0; final long randLow = rand & 0xFFFFFFFFL; final long boundLow = bound & 0xFFFFFFFFL; rand >>>= 32; bound >>= 32; final long z = (randLow * boundLow >> 32); final long t = rand * boundLow + z; return rand * bound + (t >> 32) + ((t & 0xFFFFFFFFL) + randLow * bound >> 32) - (z >> 63); } /** * Exclusive on bound (which may be positive or negative), with an inner bound of 0. * If bound is negative this returns a negative long; if bound is positive this returns a positive long. The bound * can even be 0, which will cause this to return 0L every time. This uses a biased technique to get numbers from * large ranges, but the amount of bias is incredibly small (expected to be under 1/1000 if enough random ranged * numbers are requested, which is about the same as an unbiased method that was also considered).It may have * noticeable bias if the generator's period is exhausted by only calls to this method. Unlike all unbiased methods, * this advances the state by an equivalent to exactly one call to {@link #nextLong()}, where rejection sampling * would sometimes advance by one call, but other times by arbitrarily many more. *
* Credit for this method goes to Rafael Baptista's blog, * with some adaptation for signed long values and a 64-bit generator. This method is drastically faster than the * previous implementation when the bound varies often (roughly 4x faster, possibly more). It also always gets at * most one random number, so it advances the state as much as {@link #nextInt(int)} or {@link #nextLong()}. * @param bound the outer exclusive bound; can be positive or negative * @return a random long between 0 (inclusive) and bound (exclusive) */ public long nextSignedLong(long bound) { long rand = random.nextLong(); final long randLow = rand & 0xFFFFFFFFL; final long boundLow = bound & 0xFFFFFFFFL; rand >>>= 32; bound >>= 32; final long z = (randLow * boundLow >> 32); final long t = rand * boundLow + z; return rand * bound + (t >> 32) + ((t & 0xFFFFFFFFL) + randLow * bound >> 32) - (z >> 63); } /** * Returns a random non-negative integer between 0 (inclusive) and the given bound (exclusive), * or 0 if the bound is 0. The bound can be negative, which will produce 0 or a negative result. * This is almost identical to the earlier {@link #nextIntHasty(int)} except that it will perform better when the * RandomnessSource this uses natively produces 32-bit output. It was added to the existing nextIntHasty() so * existing code using nextIntHasty would produce the same results, but new code matches the API with * {@link #nextSignedLong(long)}. This is implemented slightly differently in {@link AbstractRNG}, and different * results should be expected when using code based on that abstract class. *
* Credit goes to Daniel Lemire, http://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/ * * @param bound the outer bound (exclusive), can be negative or positive * @return the found number */ public int nextSignedInt(final int bound) { return (int) ((bound * (long)random.next(31)) >> 31); } /** * Returns a random non-negative integer below the given bound, or 0 if the bound is 0 or * negative. Always makes one call to the {@link RandomnessSource#next(int)} method of the RandomnessSource that * would be returned by {@link #getRandomness()}, even if bound is 0 or negative, to avoid branching and also to * ensure consistent advancement rates for the RandomnessSource (this can be important if you use a * {@link SkippingRandomness} and want to go back before a result was produced). *
* This method changed a fair amount on April 5, 2018 to better support RandomnessSource implementations with a * slower nextLong() method, such as {@link Lathe32RNG}, and to avoid branching/irregular state advancement/modulus * operations. It is now almost identical to {@link #nextIntHasty(int)}, but won't return negative results if bound * is negative (matching its previous behavior). This may have statistical issues (small ones) if bound is very * large (the estimate is still at least a bound of a billion or more before issues are observable). Consider * {@link #nextSignedInt(int)} if the bound should be allowed to be negative; {@link #nextIntHasty(int)} is here for * compatibility with earlier versions, but the two methods are very similar. *
* Credit goes to Daniel Lemire, http://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/ * * @param bound the upper bound (exclusive) * @return the found number */ @Override public int nextInt(final int bound) { return (int) ((bound * ((long)random.next(31))) >>> 31) & ~(bound >> 31); // int threshold = (0x7fffffff - bound + 1) % bound; // for (; ; ) { // int bits = random.next(31); // if (bits >= threshold) // return bits % bound; // } } /** * Returns a random non-negative integer between 0 (inclusive) and the given bound (exclusive), * or 0 if the bound is 0. The bound can be negative, which will produce 0 or a negative result. * Uses an aggressively optimized technique that has some bias, but mostly for values of * bound over 1 billion. This method is no more "hasty" than {@link #nextInt(int)}, but it is a little * faster than that method because this avoids special behavior for when bound is negative. *
* Credit goes to Daniel Lemire, http://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/ * * @param bound the outer bound (exclusive), can be negative or positive * @return the found number */ public int nextIntHasty(final int bound) { return (int) ((bound * (random.nextLong() & 0x7FFFFFFFL)) >> 31); } /** * Generates random bytes and places them into the given byte array, modifying it in-place. * The number of random bytes produced is equal to the length of the byte array. Unlike the * method in java.util.Random, this generates 8 bytes at a time, which can be more efficient * with many RandomnessSource types than the JDK's method that generates 4 bytes at a time. *
* Adapted from code in the JavaDocs of {@link Random#nextBytes(byte[])}. *
* @param bytes the byte array to fill with random bytes; cannot be null, will be modified * @throws NullPointerException if the byte array is null */ public void nextBytes(final byte[] bytes) { for (int i = 0; i < bytes.length; ) for (long r = random.nextLong(), n = Math.min(bytes.length - i, 8); n-- > 0; r >>>= 8) bytes[i++] = (byte) r; } /** * Get a random integer between Integer.MIN_VALUE to Integer.MAX_VALUE (both inclusive). * * @return a 32-bit random int. */ @Override public int nextInt() { return random.next(32); } /** * Get up to 32 bits (inclusive) of random output; the int this produces * will not require more than {@code bits} bits to represent. * * @param bits an int between 1 and 32, both inclusive * @return a random number that fits in the specified number of bits */ @Override public int next(int bits) { return random.next(bits); } public RandomnessSource getRandomness() { return random; } public void setRandomness(RandomnessSource random) { this.random = random; } /** * Creates a copy of this RNG; it will generate the same random numbers, given the same calls in order, as this RNG * at the point copy() is called. The copy will not share references with this RNG. * * @return a copy of this RNG */ @Override public RNG copy() { return new RNG(random.copy()); } /** * Generates a random 64-bit long with a number of '1' bits (Hamming weight) equal on average to bitCount. * For example, calling this with a parameter of 32 will be equivalent to calling nextLong() on this object's * RandomnessSource (it doesn't consider overridden nextLong() methods, where present, on subclasses of RNG). * Calling this with a parameter of 16 will have on average 16 of the 64 bits in the returned long set to '1', * distributed pseudo-randomly, while a parameter of 47 will have on average 47 bits set. This can be useful for * certain code that uses bits to represent data but needs a different ratio of set bits to unset bits than 1:1. *
* This method is deprecated because it really only finds usage in GreasedRegion, so it has been moved there and * made so it can take any RandomnessSource as a parameter, including any IRNG or RNG. * * @param bitCount an int, only considered if between 0 and 64, that is the average number of bits to set * @return a 64-bit long that, on average, should have bitCount bits set to 1, potentially anywhere in the long * @deprecated see the version in GreasedRegion, {@link GreasedRegion#approximateBits(RandomnessSource, int)} */ @Deprecated public long approximateBits(int bitCount) { if (bitCount <= 0) return 0L; if (bitCount >= 64) return -1L; if (bitCount == 32) return random.nextLong(); boolean high = bitCount > 32; int altered = (high ? 64 - bitCount : bitCount), lsb = NumberTools.lowestOneBit(altered); long data = random.nextLong(); for (int i = lsb << 1; i <= 16; i <<= 1) { if ((altered & i) == 0) data &= random.nextLong(); else data |= random.nextLong(); } return high ? ~(random.nextLong() & data) : (random.nextLong() & data); } /** * Gets a somewhat-random long with exactly 32 bits set; in each pair of bits starting at bit 0 and bit 1, then bit * 2 and bit 3, up to bit 62 and bit 3, one bit will be 1 and one bit will be 0 in each pair. *
* Not exactly general-use; meant for generating data for GreasedRegion. This is deprecated in favor of the version * in GreasedRegion. * @return a random long with 32 "1" bits, distributed so exactly one bit is "1" for each pair of bits * @deprecated See {@link GreasedRegion#randomInterleave(RandomnessSource)} for where this will be moved */ @Deprecated public long randomInterleave() { long bits = nextLong() & 0xFFFFFFFFL, ib = ~bits & 0xFFFFFFFFL; bits |= (bits << 16); ib |= (ib << 16); bits &= 0x0000FFFF0000FFFFL; ib &= 0x0000FFFF0000FFFFL; bits |= (bits << 8); ib |= (ib << 8); bits &= 0x00FF00FF00FF00FFL; ib &= 0x00FF00FF00FF00FFL; bits |= (bits << 4); ib |= (ib << 4); bits &= 0x0F0F0F0F0F0F0F0FL; ib &= 0x0F0F0F0F0F0F0F0FL; bits |= (bits << 2); ib |= (ib << 2); bits &= 0x3333333333333333L; ib &= 0x3333333333333333L; bits |= (bits << 1); ib |= (ib << 1); bits &= 0x5555555555555555L; ib &= 0x5555555555555555L; return (bits | (ib << 1)); } /** * Gets the minimum random long between 0 and {@code bound} generated out of {@code trials} generated numbers. * Useful for when numbers should have a strong bias toward zero, but all possible values are between 0, inclusive, * and bound, exclusive. * @param bound the outer exclusive bound; may be negative or positive * @param trials how many numbers to generate and get the minimum of * @return the minimum generated long between 0 and bound out of the specified amount of trials */ public long minLongOf(final long bound, final int trials) { long value = nextSignedLong(bound); for (int i = 1; i < trials; i++) { value = Math.min(value, nextSignedLong(bound)); } return value; } /** * Gets the maximum random long between 0 and {@code bound} generated out of {@code trials} generated numbers. * Useful for when numbers should have a strong bias away from zero, but all possible values are between 0, * inclusive, and bound, exclusive. * @param bound the outer exclusive bound; may be negative or positive * @param trials how many numbers to generate and get the maximum of * @return the maximum generated long between 0 and bound out of the specified amount of trials */ public long maxLongOf(final long bound, final int trials) { long value = nextSignedLong(bound); for (int i = 1; i < trials; i++) { value = Math.max(value, nextSignedLong(bound)); } return value; } /** * Gets the minimum random int between 0 and {@code bound} generated out of {@code trials} generated numbers. * Useful for when numbers should have a strong bias toward zero, but all possible values are between 0, inclusive, * and bound, exclusive. * @param bound the outer exclusive bound; may be negative or positive * @param trials how many numbers to generate and get the minimum of * @return the minimum generated int between 0 and bound out of the specified amount of trials */ public int minIntOf(final int bound, final int trials) { int value = nextSignedInt(bound); for (int i = 1; i < trials; i++) { value = Math.min(value, nextSignedInt(bound)); } return value; } /** * Gets the maximum random int between 0 and {@code bound} generated out of {@code trials} generated numbers. * Useful for when numbers should have a strong bias away from zero, but all possible values are between 0, * inclusive, and bound, exclusive. * @param bound the outer exclusive bound; may be negative or positive * @param trials how many numbers to generate and get the maximum of * @return the maximum generated int between 0 and bound out of the specified amount of trials */ public int maxIntOf(final int bound, final int trials) { int value = nextSignedInt(bound); for (int i = 1; i < trials; i++) { value = Math.max(value, nextSignedInt(bound)); } return value; } /** * Gets the minimum random double between 0 and {@code bound} generated out of {@code trials} generated numbers. * Useful for when numbers should have a strong bias toward zero, but all possible values are between 0, inclusive, * and bound, exclusive. * @param bound the outer exclusive bound * @param trials how many numbers to generate and get the minimum of * @return the minimum generated double between 0 and bound out of the specified amount of trials */ public double minDoubleOf(final double bound, final int trials) { double value = nextDouble(bound); for (int i = 1; i < trials; i++) { value = Math.min(value, nextDouble(bound)); } return value; } /** * Gets the maximum random double between 0 and {@code bound} generated out of {@code trials} generated numbers. * Useful for when numbers should have a strong bias away from zero, but all possible values are between 0, * inclusive, and bound, exclusive. * @param bound the outer exclusive bound * @param trials how many numbers to generate and get the maximum of * @return the maximum generated double between 0 and bound out of the specified amount of trials */ public double maxDoubleOf(final double bound, final int trials) { double value = nextDouble(bound); for (int i = 1; i < trials; i++) { value = Math.max(value, nextDouble(bound)); } return value; } /** * Gets the minimum random float between 0 and {@code bound} generated out of {@code trials} generated numbers. * Useful for when numbers should have a strong bias toward zero, but all possible values are between 0, inclusive, * and bound, exclusive. * @param bound the outer exclusive bound * @param trials how many numbers to generate and get the minimum of * @return the minimum generated float between 0 and bound out of the specified amount of trials */ public float minFloatOf(final float bound, final int trials) { float value = nextFloat(bound); for (int i = 1; i < trials; i++) { value = Math.min(value, nextFloat(bound)); } return value; } /** * Gets the maximum random float between 0 and {@code bound} generated out of {@code trials} generated numbers. * Useful for when numbers should have a strong bias away from zero, but all possible values are between 0, * inclusive, and bound, exclusive. * @param bound the outer exclusive bound * @param trials how many numbers to generate and get the maximum of * @return the maximum generated float between 0 and bound out of the specified amount of trials */ public float maxFloatOf(final float bound, final int trials) { float value = nextFloat(bound); for (int i = 1; i < trials; i++) { value = Math.max(value, nextFloat(bound)); } return value; } @Override public String toString() { return "RNG with Randomness Source " + random; } @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof RNG)) return false; RNG rng = (RNG) o; return random.equals(rng.random); } @Override public int hashCode() { return 31 * random.hashCode(); } /** * Gets a random portion of data (an array), assigns that portion to output (an array) so that it fills as much as * it can, and then returns output. Will only use a given position in the given data at most once; uses the * Swap-Or-Not Shuffle to accomplish this without allocations. Internally, makes 1 call to {@link #nextInt()} and * 6 calls to {@link #nextSignedInt(int)}, regardless of the data being randomized. It will get progressively less * random as output gets larger. *
* Uses approximately the same code as {@link SwapOrNotShuffler}, but without any object or array allocations. * * @param data an array of T; will not be modified. * @param output an array of T that will be overwritten; should always be instantiated with the portion length * @param can be any non-primitive type. * @return output, after {@code Math.min(output.length, data.length)} unique items have been put into it from data */ @Override public T[] randomPortion(T[] data, T[] output) { final int length = data.length, n = Math.min(length, output.length), func = nextInt(), a = nextSignedInt(length), b = nextSignedInt(length), c = nextSignedInt(length), d = nextSignedInt(length), e = nextSignedInt(length), f = nextSignedInt(length); int key, index; for (int i = 0; i < n; i++) { index = i; key = a - index; key += (key >> 31 & length); if(((func) + Math.max(index, key) & 1) == 0) index = key; key = b - index; key += (key >> 31 & length); if(((func >>> 1) + Math.max(index, key) & 1) == 0) index = key; key = c - index; key += (key >> 31 & length); if(((func >>> 2) + Math.max(index, key) & 1) == 0) index = key; key = d - index; key += (key >> 31 & length); if(((func >>> 3) + Math.max(index, key) & 1) == 0) index = key; key = e - index; key += (key >> 31 & length); if(((func >>> 4) + Math.max(index, key) & 1) == 0) index = key; key = f - index; key += (key >> 31 & length); if(((func >>> 5) + Math.max(index, key) & 1) == 0) index = key; output[i] = data[index]; } return output; } /** * Gets a random double between 0.0 inclusive and 1.0 inclusive. * * @return a double between 0.0 (inclusive) and 1.0 (inclusive) */ public double nextDoubleInclusive() { return (random.nextLong() & 0x1fffffffffffffL) * 0x1.0000000000001p-53; } /** * This returns a random double between 0.0 (inclusive) and outer (inclusive). The value for outer can be positive * or negative. Because of how math on doubles works, there are at most 2 to the 53 values this can return for any * given outer bound, and very large values for outer will not necessarily produce all numbers you might expect. * * @param outer the outer inclusive bound as a double; can be negative or positive * @return a double between 0.0 (inclusive) and outer (inclusive) */ public double nextDoubleInclusive(final double outer) { return (random.nextLong() & 0x1fffffffffffffL) * 0x1.0000000000001p-53 * outer; } /** * Gets a random float between 0.0f inclusive and 1.0f inclusive. * * @return a float between 0f (inclusive) and 1f (inclusive) */ public float nextFloatInclusive() { return random.next(24) * 0x1.000002p-24f; } /** * This returns a random float between 0.0f (inclusive) and outer (inclusive). The value for outer can be positive * or negative. Because of how math on floats works, there are at most 2 to the 24 values this can return for any * given outer bound, and very large values for outer will not necessarily produce all numbers you might expect. * * @param outer the outer inclusive bound as a float; can be negative or positive * @return a float between 0f (inclusive) and outer (inclusive) */ public float nextFloatInclusive(final float outer) { return random.next(24) * 0x1.000002p-24f * outer; } /** * Gets a random Coord that has x between 0 (inclusive) and width (exclusive) and y between 0 (inclusive) * and height (exclusive). This makes one call to randomLong to generate (more than) 31 random bits for * each axis, and should be very fast. Remember that Coord values are cached in a pool that starts able to * hold up to 255 x and 255 y for positive values, and the pool should be grown with the static method * Coord.expandPool() in order to efficiently use larger Coord values. If width and height are very large, * greater than 100,000 for either, this particular method may show bias toward certain positions due to * the "hasty" technique used to reduce the random numbers to the given size, but because most maps in * tile-based games are relatively small, this technique should be fine. *
* Credit goes to Daniel Lemire, http://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/ * * @param width the upper bound (exclusive) for x coordinates * @param height the upper bound (exclusive) for y coordinates * @return a random Coord between (0,0) inclusive and (width,height) exclusive */ public Coord nextCoord(int width, int height) { final long n = random.nextLong(); return Coord.get((int) ((width * (n >>> 33)) >> 31), (int) ((height * (n & 0x7FFFFFFFL)) >> 31)); } /** * Use that to get random cells in a rectangular map. * * @param width The map's width (bounds the x-coordinate in returned coords). * @param height The map's height (bounds the y-coordinate in returned coords). * @param size The number of elements in the returned iterable or anything * negative for no bound (in which case the iterator is infinite, it's * up to you to bound your iteration). * @return An iterable that returns random cells in the rectangle (0,0) * (inclusive) .. (width, height) (exclusive). */ public Iterable getRandomCellsIterable(final int width, final int height, final int size) { return new Iterable() { @Override public Iterator iterator() { return new Iterator() { /** * The number of elements returned so far */ int returned = 0; @Override public boolean hasNext() { return size < 0 || returned < size; } @Override public Coord next() { if (!hasNext()) throw new NoSuchElementException(); returned++; return nextCoord(width, height); } @Override public void remove() { throw new UnsupportedOperationException(); } }; } }; } /** * Gets an array of unique Coords, from (startX,startY) inclusive to (startX+width,startY+height) exclusive, in a * random order, with the array containing {@code width * height} items. * * @param startX the inclusive starting x position * @param startY the inclusive starting y position * @param width the width of the space to place Coords in, extending from startX * @param height the height of the space to place Coords in, extending from startY * @return an array containing {@code width * height} Coord items in random order, inside the given bounds */ public Coord[] getRandomUniqueCells(final int startX, final int startY, final int width, final int height) { if (width <= 0 || height <= 0) return new Coord[0]; return getRandomUniqueCells(startX, startY, width, height, new Coord[width * height]); } /** * Gets an array of unique Coords, from (startX,startY) inclusive to (startX+width,startY+height) exclusive, in a * random order, with the array containing {@code Math.min(width * height, size)} items. If size is less than width * times height, then not all Coords in the space will be used. * * @param startX the inclusive starting x position * @param startY the inclusive starting y position * @param width the width of the space to place Coords in, extending from startX * @param height the height of the space to place Coords in, extending from startY * @param size the size of the array to return; only matters if it is smaller than {@code width * height} * @return an array containing {@code Math.min(width * height, size)} Coord items in random order, inside the given bounds */ public Coord[] getRandomUniqueCells(final int startX, final int startY, final int width, final int height, final int size) { if (width <= 0 || height <= 0 || size <= 0) return new Coord[0]; return getRandomUniqueCells(startX, startY, width, height, new Coord[Math.min(width * height, size)]); } /** * Assigns to dest an array of unique Coords, from (startX,startY) inclusive to (startX+width,startY+height) * exclusive, in a random order, with dest after this is called containing the lesser of {@code width * height} or * {@code dest.length} items. This will not allocate a new array for dest, but will create a temporary int array for * handling the shuffle. * * @param startX the inclusive starting x position * @param startY the inclusive starting y position * @param width the width of the space to place Coords in, extending from startX * @param height the height of the space to place Coords in, extending from startY * @param dest a Coord array that will be modified to contain randomly-ordered Coords, but will not be resized * @return dest, now with up to its first {@code width * height} items assigned to random Coords inside the given bounds */ public Coord[] getRandomUniqueCells(final int startX, final int startY, final int width, final int height, final Coord[] dest) { if (width <= 0 || height <= 0 || dest == null || dest.length <= 0) return dest; int[] o = randomOrdering(width * height); for (int i = 0; i < o.length && i < dest.length; i++) { dest[i] = Coord.get(startX + o[i] % width, startY + o[i] / width); } return dest; } /** * Returns this RNG in a way that can be deserialized even if only {@link IRNG}'s methods can be called. * @return a {@link Serializable} view of this RNG; always {@code this} */ @Override public Serializable toSerializable() { return this; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy