I'm tired of seeing redundant and incorrect use of random utilies and incorrect probability. I vowed to release something better and that's what I'm doing today. Please delete Misc.getRandom after reading.
What's the problem?
- Manually manipulating random generator methods to reach the target domain. This bloats code and isn't readable. Leaves possibility of errors. One notable error I saw was choosing a random array element that had a chance of an array index out of bounds. int id = rewardIds[Misc.getRandom(rewardIds.length)] was something like that.
- Incorrect or unclear probabilities. If Misc.getRandom(100) == 1. Looks like a 1/100 chance, on most servers it is 1/101. I've seen too much probabilities that were clearly intended to be a round value but were off by one.
- Lack of available methods. This is the reason of the first point above.
- Concentrating on easily abstracted things.
Examples of use
Code:
if (Rand.hit(6)) {
// 1/6 chance to get here
}
Code:
if (Rand.hitPercent(50)) {
// 50% chance to get here
}
Code:
if (Rand.hitProbability(0.6)) {
// probability of 0.6 to get here
}
Code:
int[] ids = new int[] {4151, 6585, 2347, 1263};
int randomId = Rand.randElement(ids);
Code:
boolean tails = Rand.nextBoolean();
Code:
int coinsAmount = Rand.inclusive(5_000_000, 25_000_000);
Todo
I never really finished this and plan to later. I still want to add parameter validation / error handling. I also want to add a method for chosing k distinct elements from a collection of size n in O(k) time using Fisher-Yates. And a method for choosing a random element but excluding a certain index (e.g. How wilderness oblisks work, you teleport to a different oblisk than your current one). I might add support for other collections but I honestly can't see much cases for it. This is still a huge improvement from the existing random utilities and people should switch if you still use ones from pi, elvarg, ruse, maybe Vencillio and whatever else. This isn't rocket science code, I just don't want to see the next released sources with the same shit.
Make a new class called Rand.java and copy this into it.
Code:
import java.security.SecureRandom;
import java.util.List;
/**
* Used for random generation of numbers for probability events and random selection.
*
* @author Patrick/!knd6060#4741
*/
public class Rand {
private static final SecureRandom gen = new SecureRandom();
/**
* Random generator for hitting a certain probability.
*
* @Param denom The 1/denom chance that this returns true.
* @Return Whether the chance was hit.
*/
public static boolean hit(int denom) {
return gen.nextInt(denom) == 0;
}
/**
* Random generator for hitting a certain probability.
*
* @Param percent The percent rate that this returns true.
* @Return Whether the percent was hit.
*/
public static boolean hitPercent(int percent) {
return gen.nextInt(100) < percent;
}
/**
* Random generator for hitting a certain probability.
*
* @Param p The probability of success / the probability that this returns true. p must be between 0 and 1 inclusive.
* @Return Whether the probability was hit.
*/
public static boolean hitProbability(double p) {
return gen.nextDouble() < p;
}
/**
* Returns a random element of a generic list.
*
* @Param list
* @Return random element from the array
*/
public static <T> T randElement(List<T> list) {
return list.get(gen.nextInt(list.size()));
}
/**
* Returns a random element of a generic array.
*
* @Param array
* @Return random element from the array
*/
public static <T> T randElement(T[] array) {
return array[gen.nextInt(array.length)];
}
/**
* Returns a random element of a int[] array.
*
* @Param array
* @Return random element from the array
*/
public static int randElement(int[] array) {
return array[gen.nextInt(array.length)];
}
/**
* Returns a random element of a boolean[] array.
*
* @Param array
* @Return random element from the array
*/
public static boolean randElement(boolean[] array) {
return array[gen.nextInt(array.length)];
}
/**
* Returns a random element of a double[] array.
*
* @Param array
* @Return random element from the array
*/
public static double randElement(double[] array) {
return array[gen.nextInt(array.length)];
}
/**
* Returns a random element of a byte[] array.
*
* @Param array
* @Return random element from the array
*/
public static byte randElement(byte[] array) {
return array[gen.nextInt(array.length)];
}
/**
* Returns a random element of a char[] array.
*
* @Param array
* @Return random element from the array
*/
public static char randElement(char[] array) {
return array[gen.nextInt(array.length)];
}
/**
* Returns a random element of a float[] array.
*
* @Param array
* @Return random element from the array
*/
public static float randElement(float[] array) {
return array[gen.nextInt(array.length)];
}
/**
* Returns a random element of a short[] array.
*
* @Param array
* @Return random element from the array
*/
public static short randElement(short[] array) {
return array[gen.nextInt(array.length)];
}
/**
* Returns a random element of a long[] array.
*
* @Param array
* @Return random element from the array
*/
public static long randElement(long[] array) {
return array[gen.nextInt(array.length)];
}
public static int inclusive(int low, int high) {
return low + gen.nextInt(high - low + 1);
}
public static boolean nextBoolean() {
return gen.nextBoolean();
}
/**
*
* @Param bound
* @Return random number between 0 inclusive and bound exclusive
*/
public static int nextInt(int bound) {
return gen.nextInt(bound);
}
/**
*
* @Param bound
* @Return random number between 0 inclusive and bound inclusive
*/
public static int nextInclusiveInt(int bound) {
return gen.nextInt(bound + 1);
}
public static double nextDouble() {
return gen.nextDouble();
}
public static double nextFloat() {
return gen.nextFloat();
}
}
Note: there's an important reason why I decided not to provide a nextLong() method. The seed size (48 bits) for the random generator is less than 64 bits so it is impossible to generate all possible long values and you would have statistically inconsistent randomness. Very rare that you would even need such a method.
Note2: You can use ThreadLocalRandom instead of SecureRandom if you have an application with high concurrent usage of this class at the cost of losing cryptographic security of the prng.