Java – how to write a probabilistic algorithm that can be easily maintained?
Suppose I want to create a game At the beginning of the game, the player will choose a monster
It's easy to choose monsters fairly
// get all monsters with equal chance
public Monster getMonsterFair(){
Monster[] monsters = {new GoldMonster(),new SilverMonster(),new BronzeMonster()};
int winIndex = random.nextInt(monsters.length);
return monsters[winIndex];
}
Choose monsters unfairly
// get monsters with unequal chance
public Monster getMonsterUnFair(){
double r = Math.random();
// about 10% to win the gold one
if (r < 0.1){
return new GoldMonster();
}
// about 30% to winthe silver one
else if ( r < 0.1 + 0.2){
return new SilverMonster();
}
// about 70% to win the bronze one
else {
return new BronzeMonster();
}
}
The problem is, when I add a new monster to the game, I have to edit if else Or I'll change my chance to win goldmonster to 0.2. I have to change all 0.1 to 0.2. It's ugly and not easy to maintain
// get monsters with unequal change & special monster
public Monster getMonsterSpecial(){
double r = Math.random();
// about 10% to win the gold one
if (r < 0.1){
return new GoldMonster();
}
// about 30% to win the silver one
else if ( r < 0.1 + 0.2){
return new SilverMonster();
}
// about 50% to win the special one
else if ( r < 0.1 + 0.2 + 0.2){
return new SpecialMonster();
}
// about 50% to win the bronze one
else {
return new BronzeMonster();
}
}
How can this probabilistic algorithm be refactored so that code can be easily maintained when adding new monsters and adjusting the chances of winning monsters?
Solution
Basically what @ Egor skriptunoff said This should be easy to expand You can use the collection of class < monster > If you don't want to use enumeration
enum Monster {
GOLD(1),SILVER(3),BRONZE(6) // pseudo probabilities
private int weight;
// constructor etc..
}
public Monster getMonsterSpecial() {
List<Monster> monsters = new ArrayList<>();
for(Monster monsterType : Monster.values()) {
monsters.addAll(Collections.nCopies(monsterType.getWeight(),monsterType));
}
int winIndex = random.nextInt(monsters.length);
return monsters.get(winIndex);
}
You may be able to enumerate the monster plural and point it to a class if you also want to instantiate the monster class I just want to make this example clearer
