Solved Chances (%) with for loops

Discussion in 'Spigot Plugin Development' started by Arjan, Aug 11, 2015.

  1. Hello,

    So I've been trying to get my head around this for the past couple of hours. What I have (in a config file) is an item and a chance. The chance represents, duh, the chance of the item to be chosen. However, I'm running into problems when trying to implement this.

    I've got a custom 9 slot inventory and every slot should be treated separately.
    I'm using this loop to loop through every slot:
    Code (Text):
    for(int i = 0; i < inv.getSize(); i++){
    }
    Setting slots to specific items is working all great although I need those chances to be calculated for every slot separately. Let's say I have an Iron Ingot at 75% and a Gold Ingot at 25%.
    How would I, per slot, calculate which one of the two items will be placed?
    By the way, I think I managed to do it a little bit, but my troubles really start when I try to add a third item to the existing two. (Iron, Gold and a Diamond. 75%, 20% and 5%).
     
  2. How do you store the ItemStacks and their chances? Are they loaded to a HashMap or are they still in a config? If so, how is the format in the config, did you use the getConfig()#set(path, ItemStack)?
     
  3. I have an array which stores the integers of the chances. These are pulled out of the config. And my question is more about the chance, not about the ItemStacks.
     
  4. I had written something similar, you can find the code for it here: https://github.com/domisum/Airdrops/blob/master/src/item/ConfigItemManager.java

    This is the method that is important for you:
    Code (Text):
    public ItemStack getRandomItem()
        {
            if(itemStacks.size() == 0)
                return null;
           
            int dropChanceSum = 0;
            for(ConfigItemStack cis : itemStacks)
                dropChanceSum += cis.getDropChance();
           
            int randomNumber = random.nextInt(dropChanceSum);
           
            int dropChanceTillNow = 0;
            for(ConfigItemStack cis : itemStacks)
            {
                dropChanceTillNow += cis.getDropChance();
                if(dropChanceTillNow >= randomNumber)
                    return cis.clone();
            }
           
            return null;
        }
    If I modify the method to something that may fit you I end up with this:

    Code (Text):
    private int[]                    chances;
       
        public int getRandomItemStackID()
        {
            // get sum of all chances
            int dropChanceSum = 0;
            for(int i = 0; i < chances.length; i++)
                dropChanceSum += chances[i];
           
            int randomNumber = new Random().nextInt(dropChanceSum);
           
            // loop through the chances again until the sum of them is bigger than the random number within the sum of all chances
            int dropChanceTillNow = 0;
            for(int i = 0; i < chances.length; i++)
            {
                dropChanceTillNow += chances[i];
                if(dropChanceTillNow >= randomNumber)
                    return i;
            }
           
            // should never happen
            return -1;
        }
    Note that this is designed to work when the chances do not add up to 100%.
     
  5. Maybe I need to explain it a little more. In the config I put this for example:
    Code (Text):
    Item: [1,2,3]
    Chance: [25,25,50]
    Now, how would I calculate what will be put in each slot?
    Every slot should be separately calculated to see if the slot should contain item 1, 2 or 3.
     
  6. I added another method to my original method to do this for you. I expect that you can already load the items and the chances from the config to an array. The method loops through all the slots of the inventory and calculates a random itemstack id with the getRandomItemStackID() method (which will give either 0, 1, 2, assuming the arrays have a size of 3 like in your answers). Then the correct itemstack is fetched from the itemstack array with the itemstack id and added to the inventory at the specified slot.

    Code (Text):

        private int[]                    chances;
        private ItemStack[]                itemStacks;
     
        public void fillInventoryWithRandomItems(Inventory inv)
        {
            for(int slot = 0; slot < inv.getSize(); slot++)
                inv.setItem(slot, itemStacks[getRandomItemStackID()]);
        }
     
        private int getRandomItemStackID()
        {
            // get sum of all chances
            int dropChanceSum = 0;
            for(int i = 0; i < chances.length; i++)
                dropChanceSum += chances[i];
         
            int randomNumber = new Random().nextInt(dropChanceSum);
         
            // loop through the chances again until the sum of them is bigger than the random number within the sum of all chances
            int dropChanceTillNow = 0;
            for(int i = 0; i < chances.length; i++)
            {
                dropChanceTillNow += chances[i];
                if(dropChanceTillNow >= randomNumber)
                    return i;
            }
         
            // should never happen
            return -1;
        }
     
     
  7. Got it almost working right now. The chances are doing great although it fills the whole inventory with the same item instead of calculating separately. I had it working before so I must have forgot something.
    Code (Text):

    for(int i = 0; i < inv.getSize(); i++){
                inv.setItem(i, new ItemStack(Material.STAINED_GLASS_PANE, 1, (short) getTierColor(Main.plugin.getConfig().getString("TierColor." + arrayID))));
            }
     
  8. What does the function #getTierColor(String) do, does it contain the randomization?
     
  9. No, it looks for the string and returns an integer.
    Code (Text):

    private static int getTierColor(String color){
            if(color.equals("WHITE")) return 0;
            if(color.equals("ORANGE")) return 1;
            if(color.equals("MAGENTA")) return 2;
            if(color.equals("LIGHT_BLUE")) return 3;
            if(color.equals("YELLOW")) return 4;
            if(color.equals("LIME")) return 5;
            if(color.equals("PINK")) return 6;
            if(color.equals("GRAY")) return 7;
            if(color.equals("LIGHT_GRAY")) return 8;
            if(color.equals("CYAN")) return 9;
            if(color.equals("PURPLE")) return 10;
            if(color.equals("BLUE")) return 11;
            if(color.equals("BROWN")) return 12;
            if(color.equals("GREEN")) return 13;
            if(color.equals("RED")) return 14;
            if(color.equals("BLACK")) return 15;
            else return 0;
        }
     
    EDIT: My fault. I forgot to put the randomizer within the for loop so it only generated a random item once. So, solved.
     
    #9 Arjan, Aug 11, 2015
    Last edited: Aug 11, 2015