Multiple ItemStacks put in one arrayList?

Discussion in 'Spigot Plugin Development' started by kadesa, Apr 18, 2017.

  1. OK, this is definitely a d00b thing but isn't this Forums page for exactly that?

    anyways, i have multiple ItemStacks and i want to add then to an array list so then i can later access an item stack at random(by chance) to put in a LootChest.

    what my question is is.

    A) How do i put multiple ItemStacks into an ArrayList.
    B) How do I access the array list wile each Item has its own chance of being chosen, then put it in a chest.

    I know that this is fairly complex, but i know that there are smart people in here that are willing to help.
    I am not asking for spoon feeding, just a simple way of understanding how to do it.


    Thanks in advance,

    Kadeska23

    P.S. My username was meant to be Kadeska23 but i messed up on registration, so i am stuck with this until i can donate to unlock the ability to change my name.
     
  2. 1) ArrayList.add(E e)?
    2) To get a random element, use Java's random class and use nextInt with an upper boundary as the size of your ArrayList. This returned number will be the index of a random element in your ArrayList that you can use.
     
    • Like Like x 2
  3. ok grate, but can you point me to the random class.

    also how would i make each item have its own chance of being chosen>
     
  4. If you want each item to have it's own small chance of being chosen, use a HashMap. Make the itemstack the key and the value is the chance (probably want a double for this).

    The way I'd do it is to then clone the itemstacks in a new array, shuffle them with Collections.shuffle(...), then go through them and check if a random chance is less than the chance of that itemstacks chance. E.g. if (random.nextDouble() <= itemChance) {//Do this }
     
    • Useful Useful x 1
  5. I like that, i will try to figure that out tomorrow.
    Till then, i'm still opened for new ideas!
     
  6. For your first problem, just add every itemstack to an ArrayList.
    For your second problem, as Hunky524 told you, create a Random, then create a int using the randoms .nextInt(arraylist.size());
    then you can get to your arraylist and select the index you just created using the random, here's an example!

    Code (Text):
    ArrayList<ItemStack> list = new ArrayList<>();
    //Add your itemstacks here
    list.add(itemstack);

    //To get a random stack
    Random r = new Random();
    ItemStack result = list.get(r.nextInt(list.size));
     
    • Like Like x 1
  7. 1)Use StrangeOne101's way
    2) I suggest you create a method for this for easy execution. You will need a no. between 1 and 100 because thats how percentages work. So, im gonna show u a basic example, im writing it off my mind so there may be small errors that u should be able to fix yourself.
    Code (Text):
    public boolean applyChance(int chance){
          Random rnd = new Random();
          int randno = rand.nextInt((100 - 1) + 1) + 1;
    if (chance>=rndno){
    return true;
    }
    return false;
    }
     
     
    • Like Like x 1
    • Useful Useful x 1
  8. A List (or ArrayList) is a List, it can hold multiple Objects of the specified Object the List holds.

    Code (Text):
    List<ItemStack> items = new ArrayList<>();
    items.add(new ItemStack(Material.AIR));
    items.add(new ItemStack(Material.GRASS));
    If you wanted to store multiple item stacks in a HashMap for the same Key, the concept would be slightly different:
    Code (Text):
    HashMap<UUID, ItemStack[]> items = new HashMap<>();

    items.put(player.getUniqueId(), new ItemStack[] {stack1, stack2, stack3, stack4});

    ItemStack[] stacks = items.get(player.getUniqueId()); // returns ItemStack[]

    ItemStack stack2 = stacks[1];
    As for the random chance, you can do something like this. Note that the method getQueuedSpecific() returns List<UUID>, and GameType is an Enum.
    Code (Text):
    public UUID getRandomQueued(GameType type, String kit) {
            return getQueuedSpecific(type, kit).stream().toArray(UUID[]::new)[new Random().nextInt(getQueuedSpecific(type, kit).stream().toArray(UUID[]::new).length)];
        }
    Hopefully that helps you. :)
     
  9. A good method to start with, but I still suggest using doubles over intergers. Doubles are just more precise, and doing rand.nextDouble() * 100 works just the same as what you have, apart from it would work with chances like 0.5 ;)
     
    • Like Like x 1
  10. Mas

    Mas

    ThreadLocalRandom is a much faster implementation of Random which is ideally what you should use.
     
  11. Talking percentages, you can just use a no. between 1 and 100. but if you are talkign about geting 0.5 out of 1, its the same as getting 50. And getting a decimal in a 1-100 randomizer would mean that the possible results are more than 100 and tbh not even required. Personally I'd prefer this over doubles since usually u dont have to check percentages like 50.66789 or something, xD but I guess if u really wanna do that.... lol

    You are correct my friend :D. As I said, I just took that method of the top of my mind. ThreadLocalRandom is faster because it implements one per thread and there are some performance degrading with Random being used in multiple threads
     
  12. Sorry, I should have clarified lol. I meant percentages such as 0.05% or 96.66%. If you didn't want that, then ints are fine. But if you ever want to expand past that, doubles work well ;)
     
  13. tl;dr; for a uniform distribution (equal possibility for each entry), use a List<ItemStack> with ThreadLocalRandom::nextInt and List::size as upper bound (which will yield a number between 0 and n - 1, which are all possible indices for the List - given it's not empty)

    For anything non uniform (entries have their own, different probability), use a RangeMap
    Code (pseudo (Unknown Language)):
    lower = max
    upper = lower + chance
    map.put(range(lower, upper), item)
    max = upper
    RangeMap is provided by Guava, and gives you a faster lookup than Lists and the solution provided by @StrangeOne101 (if the probability is not uniform, you'd have to check all entries). You grab a number between 0 and max, and call
    Code (pseudo (Unknown Language)):
    map.get(random)
    for the item.

    Also, no shuffling is required, the index is already random.
     
    • Like Like x 1
    • Winner Winner x 1
  14. can you explain more on why ThreadLocalRandom is a much faster implementation of Random, I will look over the java-docs later, but can you summarize it please?

    Also, All of your guys support is much appreciated.
    Thank You!
    :)
     
  15. Random is thread safe for use by multiple threads. But if multiple threads use the same instance of Random, the same seed is shared by multiple threads. This causes a contradiction between multiple threads and so leads to performance degradation. ThreadLocalRandom has a Random instance per thread and so protects against the earlier mentioned contradiction. Therefore Making ThreadLocalRandom faster than Random .Hopefully this helped.
     
  16. so i can do something like this?
    Code (Text):
    ThreadLocalRandom random = ThreadLocalRandom.current();
    if (random.nextDouble() <= itemChance) {//Do this }
    Also I would have to give each item a chance Number somehow.
     
  17. No, You use the following,
    Code (Text):
    ThreadLocalRandom random = ThreadLocalRandom.current();
    if ((random.nextDouble() *100)<= itemChance) {//Do this }
    To give a chance to each Item, Make a Hashmap
    Code (Text):
    HashMap<ItemStack,double> chances = new HashMap<ItemStack,double>();
     
    Then add all ItemStacks and chances to it as you wish, Im sure you know how to do that xD.
    Then get the Chance for each ItemStack as needed and use the above mentioned code to check if the chance is favouring or not.
    Hope this info helps ya :D
     
  18. Might I add that ThreadLocalRandom also has a fair few more methods to use, some of which can help vastly in efficiency, namely

    next<VarName>(lower, upper)
     
    • Agree Agree x 1
  19. Since I had no idea what exactly the rangemap did, here are some code examples for anyone else who is confused - It's actually a really useful:

    https://www.leveluplunch.com/java/examples/guava-rangemap-example/

    https://javahowtodoit.wordpress.com/2014/09/09/guava-rangemap-how-to-use-it-example/
     
  20. My IDE (Eclipes tells me that "The operator <= is undefined for the argument type(s) double, String"
    EDIT: I fixed it
    Here is my class.

    Code (Text):
    public enum Tier1Armor {
        Leather_Chest("50");
     
        public Boolean IsCraftable;
        public Boolean IsUpgradable;
        public Boolean IsFoundInLoot;
        public Boolean IsBossDrop;
        public String Tier1Chance;
     
        public void AddItemToChest() {
            ThreadLocalRandom random = ThreadLocalRandom.current();
         
            if ((random.nextDouble() *100)<= Tier1Chance) {
             
            }
        }
     
     
        private Tier1Armor(String chance) {
            this.Tier1Chance = chance;
            if (Armor.Tier1.GetIsCraftable = true) {
                IsCraftable = true;
            } else {
                IsCraftable = false;
            }
            if (Armor.Tier1.GetIsUpgradable = true) {
                IsUpgradable = true;
            } else {
                IsUpgradable = false;
            }
            if (Armor.Tier1.GetIsFoundInLoot = true) {
                IsFoundInLoot = true;
            } else {
                IsFoundInLoot = false;
            }
            if (Armor.Tier1.GetIsBossDrop = true) {
                IsBossDrop = true;
            } else {
                IsBossDrop = false;
            }
        }
    }
     
     
    #20 kadesa, Apr 19, 2017
    Last edited: Apr 19, 2017