Thread: A superiour random utility

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

    Join Date
    Sep 2016
    Posts
    153
    Thanks given
    66
    Thanks received
    61
    Rep Power
    374
    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.
    	 *
    	 *    @[Only registered and activated users can see links. ] denom The 1/denom chance that this returns true.
    	 *    @[Only registered and activated users can see links. ] Whether the chance was hit.
    	 */
    	public static boolean hit(int denom) {
    		return gen.nextInt(denom) == 0;
    	}
    
    	/**
    	 * Random generator for hitting a certain probability.
    	 *
    	 *    @[Only registered and activated users can see links. ] percent The percent rate that this returns true.
    	 *    @[Only registered and activated users can see links. ] Whether the percent was hit.
    	 */
    	public static boolean hitPercent(int percent) {
    		return gen.nextInt(100) < percent;
    	}
    
    
    	/**
    	 * Random generator for hitting a certain probability.
    	 *
    	 *    @[Only registered and activated users can see links. ] p The probability of success / the probability that this returns true. p must be between 0 and 1 inclusive.
    	 *    @[Only registered and activated users can see links. ] Whether the probability was hit.
    	 */
    	public static boolean hitProbability(double p) {
    		return gen.nextDouble() < p;
    	}
    
    	/**
    	 * Returns a random element of a generic list.
    	 *
    	 *    @[Only registered and activated users can see links. ] list
    	 *    @[Only registered and activated users can see links. ] 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.
    	 *
    	 *    @[Only registered and activated users can see links. ] array
    	 *    @[Only registered and activated users can see links. ] 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.
    	 *
    	 *    @[Only registered and activated users can see links. ] array
    	 *    @[Only registered and activated users can see links. ] 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.
    	 *
    	 *    @[Only registered and activated users can see links. ] array
    	 *    @[Only registered and activated users can see links. ] 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.
    	 *
    	 *    @[Only registered and activated users can see links. ] array
    	 *    @[Only registered and activated users can see links. ] 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.
    	 *
    	 *    @[Only registered and activated users can see links. ] array
    	 *    @[Only registered and activated users can see links. ] 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.
    	 *
    	 *    @[Only registered and activated users can see links. ] array
    	 *    @[Only registered and activated users can see links. ] 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.
    	 *
    	 *    @[Only registered and activated users can see links. ] array
    	 *    @[Only registered and activated users can see links. ] 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.
    	 *
    	 *    @[Only registered and activated users can see links. ] array
    	 *    @[Only registered and activated users can see links. ] 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.
    	 *
    	 *    @[Only registered and activated users can see links. ] array
    	 *    @[Only registered and activated users can see links. ] 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();
    	}
    
    	/**
    	 *
    	 *    @[Only registered and activated users can see links. ] bound
    	 *    @[Only registered and activated users can see links. ] random number between 0 inclusive and bound exclusive
    	 */
    	public static int nextInt(int bound) {
    		return gen.nextInt(bound);
    	}
    
    	/**
    	 *
    	 *    @[Only registered and activated users can see links. ] bound
    	 *    @[Only registered and activated users can see links. ] 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
    153
    Thanks given
    66
    Thanks received
    61
    Rep Power
    374
    bump
    Reply With Quote  
     

  3. #3  
    Registered Member
    Join Date
    May 2017
    Posts
    61
    Thanks given
    12
    Thanks received
    32
    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  
    Respected Member

    Corey's Avatar
    Join Date
    Feb 2012
    Posts
    1,335
    Thanks given
    986
    Thanks received
    1,303
    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)
    [Only registered and activated users can see links. ]

    [Only registered and activated users can see links. ]
    Spoiler for .:


    Reply With Quote  
     

  6. Thankful user:


  7. #5  
    Registered Member

    Join Date
    Sep 2016
    Posts
    153
    Thanks given
    66
    Thanks received
    61
    Rep Power
    374
    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
    61
    Thanks given
    12
    Thanks received
    32
    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  
    Textures developer

    Kris's Avatar
    Join Date
    Jun 2016
    Age
    22
    Posts
    3,472
    Thanks given
    625
    Thanks received
    2,166
    Rep Power
    3829
    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>.
    Spoiler for penis too large:

    [Only registered and activated users can see links. ]

    Discord: Kris#1337
    Reply With Quote  
     

  10. #8  
    Registered Member

    Join Date
    Sep 2016
    Posts
    153
    Thanks given
    66
    Thanks received
    61
    Rep Power
    374
    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 Downloads
    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
  •