Reputation: 27
I would like to be able to return (and in our case, for the example, display) an item of an enumeration, according to a certain predefined percentage of chance for each item. An illustration in code of this enumeration just below :
package me.lucas.test;
public enum Item {
ITEM_1("Item 1", 30),
ITEM_2("Item 2", 30),
ITEM_3("Item 3", 10),
ITEM_4("Item 4", 65);
private final String name;
private final int percentage;
Item(String name, int percentage) {
this.name = name;
this.percentage = percentage;
}
public String getName() {
return name;
}
public int getPercentage() {
return percentage;
}
}
Also, these items will be stored in a List.
package me.lucas.test;
import java.util.ArrayList;
import java.util.List;
public class Program {
private final List<Item> items = new ArrayList<>();
/**
* Displays an item among those in the list, according to their percentage chance of appearing.
* @param items The items
*/
public void displayItem(List<Item> items) {
Item item;
item = ?
System.out.println("Selected item : " + item.getName() + " with percentage : " + item.getPercentage());
}
}
Namely that, as in this example, two items can have the same percentage of chance to appear.
I also looked at the following topic (Java Random Percentage Chance) but in my case, the percentages are not predefined in the expressions directly but in the enumeration.
So I would appreciate your help. Thank you in advance for taking the time to help me.
Upvotes: 0
Views: 1673
Reputation: 18245
BE SIMPLE!!!
percentage
count each.public class Foo {
public static void main(String... args) {
Item[] items = generateItemArray();
Random random = new Random();
while (true) {
System.out.println(items[random.nextInt(items.length)]);
}
}
private static Item[] generateItemArray() {
List<Item> items = new ArrayList<>();
for (Item item : Item.values())
for (int i = 0; i < item.percentage; i++)
items.add(item);
Collections.shuffle(items);
return items.toArray(Item[]::new);
}
public enum Item {
ITEM_1("Item 1", 30),
ITEM_2("Item 2", 30),
ITEM_3("Item 3", 10),
ITEM_4("Item 4", 65);
private final String name;
private final int percentage;
Item(String name, int percentage) {
this.name = name;
this.percentage = percentage;
}
}
}
Upvotes: 1
Reputation: 135
Visually speaking you implement a Wheel of Chance
The wheel will land on any position 1 to 100. Now you just need to read out, which possibilities are at this position. If the sum is < 100 there may be nothing in this position. If the sum is > 100 there may be more than one item in this position.
All Percentages are wrapping from 1 to 100 - achieved by modulo. The random Number you generate is between 1 and 100, or in this case between 0 and 99 (see Javadoc of Random).
In Code this could look as follows:
public class RandomExample<T extends Object> {
List<Item> items = new LinkedList<>();
Random rand = new Random();
public void addItem(int percentage, T object) {
items.add(new Item(percentage, object));
}
public List<Item> getRandom() {
List<Item> result = new ArrayList<>();
int hit = rand.nextInt(100);
items.forEach(i -> {
if(i.isHit(hit)) {
result.add(i);
}
});
return result;
}
public class Item {
private int percentage;
private T object;
private int hitLow;
private int hitHigh;
public Item(int percentage, T object) {
this.percentage = percentage;
this.object = object;
int sum = 0;
for(Item i : items) {
sum+=i.getPercentage();
}
hitLow = sum % 100;
hitHigh = (sum+percentage) % 100;
}
public int getPercentage() {
return percentage;
}
public T getObject() {
return object;
}
public boolean isHit(int hitVal) {
boolean isHit = hitLow == hitHigh; //exactly 100%
isHit |= hitLow <= hitVal && hitHigh >= hitVal;
return isHit;
}
}
}
The method RandomExample.Item.isHit(int)
still needs an extra condition to handle chances correctly, which wrap around 100 (eg. hitLow = 90
and hitHigh = 10
). But you get the concept and should be able to adapt it to your needs.
Another question you need to ask yourself is: what happens if somebody passes a percentage greater than 100. My intuition says you should throw an exception. But that is for you to decide and implement.
Upvotes: 1