Thread: A superiour random utility

Results 1 to 8 of 8
  1. #1 A superiour random utility 
    Registered Member

    Join Date
    Sep 2016
    Posts
    181
    Thanks given
    84
    Thanks received
    74
    Rep Power
    452
    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.
    Reply With Quote  
     

  2. #2  
    Registered Member

    Join Date
    Sep 2016
    Posts
    181
    Thanks given
    84
    Thanks received
    74
    Rep Power
    452
    bump
    Reply With Quote  
     

  3. #3  
    Registered Member
    Join Date
    May 2017
    Posts
    62
    Thanks given
    12
    Thanks received
    34
    Rep Power
    31
    Not super familiar with Java, aren't the overloads for the arrays of primitives unnecessary since you have the generic T[] overload?
    And I think you could use Iterable<T> instead of List<T>, so you can support Set, Queue etc?
    Reply With Quote  
     

  4. Thankful user:


  5. #4  
    Blurite

    Corey's Avatar
    Join Date
    Feb 2012
    Age
    26
    Posts
    1,491
    Thanks given
    1,245
    Thanks received
    1,729
    Rep Power
    5000
    Quote Originally Posted by testicles View Post
    Not super familiar with Java, aren't the overloads for the arrays of primitives unnecessary since you have the generic T[] overload?
    And I think you could use Iterable<T> instead of List<T>, so you can support Set, Queue etc?
    Java doesn't support primitive generics (yet)
    Attached image
    Reply With Quote  
     

  6. Thankful user:


  7. #5  
    Registered Member

    Join Date
    Sep 2016
    Posts
    181
    Thanks given
    84
    Thanks received
    74
    Rep Power
    452
    Quote Originally Posted by testicles View Post
    Not super familiar with Java, aren't the overloads for the arrays of primitives unnecessary since you have the generic T[] overload?
    And I think you could use Iterable<T> instead of List<T>, so you can support Set, Queue etc?
    I will look into this thanks! I dont see when it would be used and i was a bit fishy about sets since the order isnt usually preserved but it might not matter anyway, as long as you have access to the size and can grab elements at a specified index it can work. However a random element from a queue shouldnt be done, that violates the data structures and wont be required. Also this class must bot leave any side effects, so no modifying of objects. I'll look into some other daa structures though, set especially.

    Edit: iterable doesn't have a method for getting the size. I can loop over everything once to get the size and then iterate to the required element and return it though, I'll add this later. I guess queues will be added along with it then lol
    Reply With Quote  
     

  8. #6  
    Registered Member
    Join Date
    May 2017
    Posts
    62
    Thanks given
    12
    Thanks received
    34
    Rep Power
    31
    Quote Originally Posted by knd6060 View Post
    I will look into this thanks! I dont see when it would be used and i was a bit fishy about sets since the order isnt usually preserved but it might not matter anyway, as long as you have access to the size and can grab elements at a specified index it can work. However a random element from a queue shouldnt be done, that violates the data structures and wont be required. Also this class must bot leave any side effects, so no modifying of objects. I'll look into some other daa structures though, set especially.

    Edit: iterable doesn't have a method for getting the size. I can loop over everything once to get the size and then iterate to the required element and return it though, I'll add this later
    Keep in mind if a method accepts an Iterable, that it can be called using a Queue, so maybe not a good idea after all. If you really don't want your random methods to be used with queues, it's better to enforce a more concrete type than to say "this method takes an Iterable, oops you tried to use a Queue that's not allowed" and then (most likely) throw an exception.
    Looks like I'm a bit spoiled by C# syntactic sugar and LINQ

    The way I've approached this in C# for my server:

    Code:
    private static T GetRandomElement<T>(IReadOnlyCollection<T> thing)
    {
        return thing.ElementAt(SomeRandom.Next(0, thing.Count));
    }
    But as Corey mentioned Java doesn't yet have support for generic collections of primitives, this will work with any collection that implements IReadOnlyCollection and the compiler assures immutability. This works for the ones you'd commonly use, like lists and arrays.

    Code:
    static void Main(string[] args)
    {
        var intList = new List<int> { 1, 33, 96, 4 };
        Console.WriteLine(GetRandomElement(intList));
    
        var intArray = new[] { 2, 99, 123, 456 };
        Console.WriteLine(GetRandomElement(intArray));
    
        var queue = new Queue<int>();
        queue.Enqueue(36);
        queue.Enqueue(594);
        queue.Enqueue(672);
        queue.Enqueue(3);
    
        Console.WriteLine(GetRandomElement(queue));
    
        Console.ReadLine();
    }
    Alternatively you can be less specific and do this, IEnumerable I believe is the closest interface to Java's Iterable.
    Code:
    private static T GetRandomElement<T>(IEnumerable<T> thing)
    {
        var thingArray = thing.ToArray(); // I love LINQ. This gives a good explanation of why you'd do this here https://stackoverflow.com/questions/8240844/handling-warning-for-possible-multiple-enumeration-of-ienumerable
        return thingArray[SomeRandom.Next(0, thingArray.Length)];
    }
    Reply With Quote  
     

  9. #7  
    Respected Member


    Kris's Avatar
    Join Date
    Jun 2016
    Age
    26
    Posts
    3,638
    Thanks given
    820
    Thanks received
    2,642
    Rep Power
    5000
    Quote Originally Posted by knd6060 View Post
    I will look into this thanks! I dont see when it would be used and i was a bit fishy about sets since the order isnt usually preserved but it might not matter anyway, as long as you have access to the size and can grab elements at a specified index it can work. However a random element from a queue shouldnt be done, that violates the data structures and wont be required. Also this class must bot leave any side effects, so no modifying of objects. I'll look into some other daa structures though, set especially.

    Edit: iterable doesn't have a method for getting the size. I can loop over everything once to get the size and then iterate to the required element and return it though, I'll add this later. I guess queues will be added along with it then lol
    Collection<T> instead of Iterable<T>.
    Attached image
    Reply With Quote  
     

  10. #8  
    Registered Member

    Join Date
    Sep 2016
    Posts
    181
    Thanks given
    84
    Thanks received
    74
    Rep Power
    452
    Thanks for responses I'll look into them and learn about it in a bit. I dont care too much about the queues working, if user wants random wueue whatever it is possible and not an issue just a bit weird. Although how much error handling should be done in general? I feel like catching a bunch of illegal argument exception would be a pain. For Rand.hitProbability it isnt an issue if it is passed like 1.2 it will just always return true and means clamping of probability doesnt need to be done elsewhere. Negative values woul cause an error but I could return false for negatve probabilities rather than throwing a error, thoughts on this?

    Quote Originally Posted by Kris View Post
    Collection<T> instead of Iterable<T>.
    What was the reason for this? Collection does have a size() method but not a get method at index. So would still need to iterate to return. I Might have missed the point. Also Queue is still in collection but idc about queue that much anymore.
    Reply With Quote  
     


Thread Information
Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)


User Tag List

Similar Threads

  1. [KT] Small random utility library
    By nbness2 in forum Application Development
    Replies: 2
    Last Post: 09-13-2018, 12:10 AM
  2. Some Random Events
    By Eleclion in forum Tutorials
    Replies: 4
    Last Post: 05-15-2007, 11:38 PM
  3. Some Random S**t
    By Darklordants Evil Bro in forum Showcase
    Replies: 2
    Last Post: 04-13-2007, 09:42 PM
  4. A few Random Renders...
    By oblak10 in forum General
    Replies: 2
    Last Post: 04-02-2007, 04:31 AM
  5. my latest sigs :D and random GFX
    By Oblak Lol in forum Showcase
    Replies: 10
    Last Post: 03-31-2007, 10:41 PM
Posting Permissions
  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •