001package squidpony.squidmath; 002 003import java.io.Serializable; 004import java.util.Arrays; 005import java.util.Random; 006 007/** 008 * A low-quality but very fast RNG that has no apparent visual artifacts here; uses Mark Overton's CMR subcycle 009 * generator type, but modified to be especially GWT-friendly. Even though it has no visual issues when rendered as 010 * pixels, it still fails PractRand testing almost immediately. This is meant to be an answer to when people ask for 011 * a bare-minimum generator that's still "good enough" for games. It has a period of 0xFFF43787 or 4294195079, which 012 * can be exhausted in seconds if you only generate numbers in that time, but some seeds will be in a different 013 * cycle with a much lower period. The likelihood of choosing one of these seeds is low, less than a fiftieth of one 014 * percent, but it can happen. It cannot produce all possible ints in its longest cycle, and it can't produce even a 015 * fraction of all possible ints in its smallest cycle. It implements RandomnessSource, but if you just want to copy 016 * this class with no dependencies, then the class declaration can easily be changed to 017 * {@code public class BasicRandom32 extends Random implements Serializable} without any other changes. Note, it does 018 * extend java.util.Random for additional ease of integration, but doesn't use the slow {@code synchronized} keyword 019 * that Random's implementations do. 020 * <br> 021 * <a href="http://www.drdobbs.com/tools/fast-high-quality-parallel-random-number/231000484">This Dr. Dobb's article has 022 * more on this type of generator</a>. 023 * @author Mark Overton 024 * @author Tommy Ettinger 025 */ 026public class BasicRandom32 extends Random implements RandomnessSource, Serializable { 027 private static final long serialVersionUID = 1L; 028 public int state; 029 030 public BasicRandom32() 031 { 032 state = 1; 033 } 034 035 public BasicRandom32(final int seed) { 036 setState(seed); 037 } 038 039 public void setState(final int seed) 040 { 041 state = (seed ^ 0x41C64E6D) * 0x9E373 ^ (seed >>> 16); 042 } 043 044 public final long nextLong() { 045 int y = state * 0xBCFD; 046 y = (y << 17 | y >>> 15); 047 final int x = y * 0xBCFD; 048 return ((long) y << 32 ^ (state = (x << 17 | x >>> 15))); 049 050 } 051 052 /** 053 * Gets an int with at most the specified amount of bits; don't confuse this with {@link #nextInt(int)}, which gets 054 * a number between 0 and its int argument, where this draws from a different (larger) range of random results. For 055 * example, {@code next(2)} can return any 2-bit int, 056 * which is limited to 0, 1, 2, or 3. Note that if you request 0 bits, this can give you any int (32 bits). 057 * @param bits the number of bits to get, from 1 to 32 058 * @return an int with at most the specified bits 059 */ 060 public final int next(final int bits) { 061 final int y = state * 0xBCFD; 062 return (state = (y << 17 | y >>> 15)) >>> (32 - bits); 063 } 064 public final int nextInt() { 065 final int y = state * 0xBCFD; 066 return (state = (y << 17 | y >>> 15)); 067 } 068 069 /** 070 * Returns a random non-negative integer between 0 (inclusive) and the given bound (exclusive), 071 * or 0 if the bound is 0. The bound can be negative, which will produce 0 or a negative result. 072 * <br> 073 * Credit goes to Daniel Lemire, http://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/ 074 * 075 * @param bound the outer bound (exclusive), can be negative or positive 076 * @return the found number 077 */ 078 public int nextInt(final int bound) { 079 return (int) ((bound * (nextInt() & 0xFFFFFFFFL)) >> 32); 080 } 081 /** 082 * Exclusive on bound (which must be positive), with an inner bound of 0. 083 * If bound is negative or 0 this always returns 0. 084 * <br> 085 * Credit for this method goes to <a href="https://oroboro.com/large-random-in-range/">Rafael Baptista's blog</a> 086 * for the original idea, and the JDK10 Math class' usage of Karatsuba multiplication for the current algorithm. 087 * This method is drastically faster than the previous implementation when the bound varies often (roughly 4x 088 * faster, possibly more). It also always gets exactly two random ints, so by default it advances the state as much 089 * as {@link #nextLong()}. 090 * 091 * @param bound the outer exclusive bound; should be positive, otherwise this always returns 0L 092 * @return a random long between 0 (inclusive) and bound (exclusive) 093 */ 094 public long nextLong(long bound) { 095 final long rand = nextInt() & 0xFFFFFFFFL; 096 final long randLow = nextInt() & 0xFFFFFFFFL; 097 if (bound <= 0) return 0; 098 final long boundLow = bound & 0xFFFFFFFFL; 099 bound >>>= 32; 100 final long a = rand * bound; 101 final long b = randLow * boundLow; 102 return (((b >>> 32) + (rand + randLow) * (bound + boundLow) - a - b) >>> 32) + a; 103 } 104 105 /** 106 * Sets the seed using a long, by XORing the upper and lower halves of {@code seed} and passing that to 107 * {@link #setState(int)}. 108 * @param seed the initial seed 109 */ 110 @Override 111 public void setSeed(long seed) { 112 setState((int)(seed ^ seed >>> 32)); 113 } 114 /** 115 * Mutates the array arr by switching the contents at pos1 and pos2. 116 * @param arr an array of T; must not be null 117 * @param pos1 an index into arr; must be at least 0 and no greater than arr.length 118 * @param pos2 an index into arr; must be at least 0 and no greater than arr.length 119 */ 120 protected static <T> void swap(T[] arr, int pos1, int pos2) { 121 final T tmp = arr[pos1]; 122 arr[pos1] = arr[pos2]; 123 arr[pos2] = tmp; 124 } 125 126 /** 127 * Shuffle an array using the Fisher-Yates algorithm and returns a shuffled copy, freshly-allocated, without 128 * modifying elements. 129 * <br> 130 * <a href="https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle">Wikipedia has more on this algorithm</a>. 131 * 132 * @param elements an array of T; will not be modified 133 * @return a shuffled copy of elements 134 */ 135 public <T> T[] shuffle(T[] elements) { 136 final int size = elements.length; 137 final T[] array = Arrays.copyOf(elements, size); 138 for (int i = size; i > 1; i--) { 139 swap(array, i - 1, nextInt(i)); 140 } 141 return array; 142 } 143 144 /** 145 * Shuffles an array in-place using the Fisher-Yates algorithm, affecting indices from 0 (inclusive) to length 146 * (exclusive). May be useful with libGDX Array instances, which can be shuffled with 147 * {@code random.shuffleInPlace(arr.items, arr.size)}. If you don't want the array modified, use 148 * {@link #shuffle(Object[])}. 149 * <br> 150 * <a href="https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle">Wikipedia has more on this algorithm</a>. 151 * 152 * @param elements an array of T; <b>will</b> be modified 153 * @return elements after shuffling it in-place 154 */ 155 public <T> T[] shuffleInPlace(T[] elements, int length) { 156 final int size = Math.min(elements.length, length); 157 for (int i = size; i > 1; i--) { 158 swap(elements, i - 1, nextInt(i)); 159 } 160 return elements; 161 } 162 163 /** 164 * Shuffles an array in-place using the Fisher-Yates algorithm. 165 * If you don't want the array modified, use {@link #shuffle(Object[])}. 166 * <br> 167 * <a href="https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle">Wikipedia has more on this algorithm</a>. 168 * 169 * @param elements an array of T; <b>will</b> be modified 170 * @return elements after shuffling it in-place 171 */ 172 public <T> T[] shuffleInPlace(T[] elements) { 173 final int size = elements.length; 174 for (int i = size; i > 1; i--) { 175 swap(elements, i - 1, nextInt(i)); 176 } 177 return elements; 178 } 179 180 public BasicRandom32 copy() { 181 BasicRandom32 sr = new BasicRandom32(); 182 sr.state = state; 183 return sr; 184 } 185}