Several helper functions for improved random number generation
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

improved_rng.pde 5.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. import java.util.*;
  2. g g = new g();
  3. final static class g {
  4. //Loops after 48 bits of random numbers - which are sufficient for most cases. This is to increase performance
  5. Random rand = new Random();
  6. //Array shuffler, returns randomized array of arbitrary data-type
  7. //With this you have fair distribution of results, so you know exactly how long it takes to read the array - exactly as long as if it weren't random - when you read the shuffled array iteratively
  8. //(compared to reading random indices of a non-shuffled array)
  9. Object random(Object[] input) {
  10. Collections.shuffle(Arrays.asList(input));
  11. return input;
  12. }
  13. //random() functions as known from Processing
  14. float random(float floor, float ceiling) {
  15. return rand.nextFloat() * (ceiling - floor) + floor;
  16. }
  17. float random(float ceiling) {
  18. return rand.nextFloat() * ceiling;
  19. }
  20. //Returns a random integer and should not repeat the same number twice
  21. int lastResult = 0;
  22. int random(float floor, float ceiling, boolean norepetition) {
  23. float nextFloat = rand.nextFloat();
  24. int result = (int)(nextFloat * (ceiling - floor) + floor);
  25. if (norepetition) {
  26. if ((int)floor - (int)ceiling == 0) {
  27. return result;
  28. }
  29. while (lastResult == result) {
  30. nextFloat = rand.nextFloat();
  31. result = (int)(nextFloat * (ceiling - floor) + floor);
  32. }
  33. lastResult = (int)result;
  34. }
  35. return result;
  36. }
  37. int random(float ceiling, boolean norepetition) {
  38. return this.random(0.0f, ceiling, norepetition);
  39. }
  40. //Returns a random entry of an array of arbitrary data-type with probabilities
  41. Object random(Object[] input, float[] probabilities) {
  42. if (input.length != probabilities.length) {
  43. println("Probability amount doesn't match amount of objects to select from.");
  44. //Instead of return(null), runtimeException (IllegalArgumentException) might be better.
  45. return(null);
  46. }
  47. float probabilitySum = 0;
  48. for (int i = 0; i < probabilities.length; i++) {
  49. probabilitySum += probabilities[i];
  50. }
  51. if (probabilitySum != 1.0) {
  52. //We could also just throw an Exception here because it's resource hungry if the user doesn't supply probabilities that add up to exactly 1.0
  53. for (int i = 0; i < probabilities.length; i++) {
  54. probabilities[i] = map(probabilities[i], 0, probabilitySum, 0, 1);
  55. }
  56. }
  57. //Not an Alias algorithm so potentially slow on long arrays
  58. //Random r = new Random();
  59. float r = rand.nextFloat();
  60. float p = 0.0f;
  61. for (int i = 0; i < input.length; i++) {
  62. p += probabilities[i];
  63. if (r < p) {
  64. return(input[i]);
  65. }
  66. }
  67. //Should never be reached
  68. return(null);
  69. }
  70. //Returns a random float between 0 and 1, selection weighted by a given probability curve defined by vectors
  71. float random(float[][] probCurve) {
  72. //Imagine an x and y coordinate system reaching from (0,0) to (1,1).
  73. //There's a function curve that must have exactly one value per f(x).
  74. //This function curve defines the probability y per x.
  75. //This is how it works:
  76. //1. Generate 2 random values x & y
  77. //2. Check if y is in the probability curve field f(x) (beneath f(x))
  78. //3. If so, x is the random number we're looing for, else, repeat
  79. //NEEDS to have a y value for x = 0 and a y value for x = 1
  80. //NEEDS to have the x values in ascending order (in the array)
  81. boolean foundX = false;
  82. float x = 0.0;
  83. float y = 0.0;
  84. while (!foundX) {
  85. x = rand.nextFloat();
  86. y = rand.nextFloat();
  87. int pos = 0;
  88. for (int i = 0; i < probCurve.length; i++) {
  89. if (x <= probCurve[i][0]) {
  90. pos = i;
  91. break;
  92. }
  93. }
  94. if (lineIntersect(x, y, x, y+1, probCurve[pos-1][0], probCurve[pos-1][1], probCurve[pos][0], probCurve[pos][1])) {
  95. foundX = true;
  96. }
  97. }
  98. return x;
  99. }
  100. boolean lineIntersect(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4) {
  101. float uA = ((x4-x3)*(y1-y3) - (y4-y3)*(x1-x3)) / ((y4-y3)*(x2-x1) - (x4-x3)*(y2-y1));
  102. float uB = ((x2-x1)*(y1-y3) - (y2-y1)*(x1-x3)) / ((y4-y3)*(x2-x1) - (x4-x3)*(y2-y1));
  103. if (uA >= 0 && uA <= 1 && uB >= 0 && uB <= 1) {
  104. return true;
  105. }
  106. return false;
  107. }
  108. }
  109. void setup() {
  110. /*
  111. //A dice rolling twice as many sixes
  112. int[] rolls = new int[6];
  113. for (int i = 0; i < 10000; i++) {
  114. int diceRoll = (int)g.random(new Object[]{(int)g.random(0, 5), 5}, new float[]{(float)5/7, (float)2/7});
  115. rolls[diceRoll] += 1;
  116. }
  117. println(rolls);
  118. */
  119. }
  120. void draw() {
  121. /*
  122. //Prints a random float between -20 and 5 (just the same as Processings random()-function and exactly as fast)
  123. println(g.random(-20, 5));
  124. */
  125. /*
  126. //Prints an integer between 15 and 20, should never repeat the same number twice in a row
  127. println(g.random(15,20, true));
  128. */
  129. /*
  130. //An array shuffler for arbitrary data types
  131. println(g.random(new Integer[]{1, 2, 3, 4, 5}));
  132. String StringArray[] = {"eins", "zwei", "drei", "vier", "fünf"};
  133. println(g.random(StringArray));
  134. Float FloatArray[] = {1.1, 1.2, 1.3, 1.4, 1.5};
  135. println(g.random(FloatArray));
  136. */
  137. /*
  138. //Prints array entries of arbitrary data type with a given probability in floats (it's recommended to let the probability floats add up to exactly 1.0, if they don't it's way more resource hungry)
  139. Object[] entries = {"rare", "common", "808"};
  140. float[] probabilities = {0.1, 0.85, 0.05};
  141. println(g.random(entries, probabilities));
  142. */
  143. /*
  144. //Prints random floats between 0 and 1 depending on a probability curve.
  145. //Never between 0 and 0.3. Probability between 0.3 and 0.5 ramps up, and goes down again between 0.5 and 0.6, diminishing to zero at 0.95, where it ramps up again, so values between 0.95 and 1.0 are again highly probable.
  146. println(g.random(new float[][]{{0.0, 0.0}, {0.3, 0.0}, {0.5, 1.0}, {0.6, 0.3}, {0.95,0.0}, {1.0, 1.0}}));
  147. */
  148. }