2013-05-31 4 views
7

Supposto Voglio creare un gioco. All'inizio del gioco, il giocatore sceglierà un mostro.Come scrivere un algoritmo di probabilità che può essere mantenuto facilmente?

È facile scegliere il mostro in modo equo.

// 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]; 
} 

e prende il mostro ingiustamente.

// 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(); 
    } 
} 

Il problema è che, quando aggiungo un nuovo mostro al gioco, devo modificare il if-else. Oppure cambio la possibilità di vincere GoldMonster a 0.2, Devo cambiare tutti 0.1 in 0.2 . È brutto e non è facile da gestire.

// 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(); 
    } 
} 

Come può questo algoritmo probabilità può essere riscritta in modo che i codici possono essere mantenuti facilmente quando viene aggiunto un nuovo mostro e le probabilità di vincita mostri vengono regolati?

+5

Seleziona il carattere dalla posizione casuale della stringa 'GSSBBBBBBB'. Tale stringa è facile da cambiare. –

risposta

3

Fondamentalmente ciò che ha detto @Egor Skriptunoff. Questo dovrebbe scalare facilmente. È possibile utilizzare una raccolta di Class<Monster> se non si desidera utilizzare uno enum.

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); 
} 

Si potrebbe forse fare l'enum Monsters plurale, e lo hanno puntano a Class<? extends Monster> se si vuole ancora istanziare le classi di mostri. Ho solo cercato di rendere più chiaro l'esempio.

+0

+1 per usare un enum – monika

+1

Non c'è alcun segno che questo accada davvero, ma se tu avessi 1000s di mostri che potrebbero avere pesi negli anni 1000 questo potrebbe diventare un bel collo di bottiglia. – Dukeling

+1

Penso che tu intendessi 'monster.size()' –

1

Vorrei utilizzare un peso totale che aumenta con ogni mostro aggiunto.

private final Random rand = new Random(); 

public Monster getMonsterSpecial() { 
    int weight = rand.nextInt(1+2+2+5); 
    if ((weight -= 1) < 0) return new GoldMonster(); 
    if ((weight -= 2) < 0) return new SilverMonster(); 
    if ((weight -= 2) < 0) return new SpecialMonster(); 
    // 50% chance of bronze 
    return new BronzeMonster(); 
} 
+0

Richiede ancora che venga aggiunta un'istruzione if quando si aggiunge un mostro. – Dukeling

+0

@Dukeling In entrambi i casi devi aggiungere qualcosa e una linea non è tanto da mantenere credo. A volte, avendo una soluzione più completa, puoi oscurare quello che realmente sta facendo. ;) –

+1

Penso che l'ideale sarebbe una soluzione in cui è possibile aggiungere mostri senza dover modificare il codice (quindi può essere fatto durante il runtime), che [la mia risposta] (http://stackoverflow.com/a/16858940/1711796) può fornire. Non è che penso che qualcuno aggiorni i giochi durante il runtime, anche per gli MMO. – Dukeling

1

Si basa su Peter's answer, appena più gestibile. Tutto quello che devi fare è aggiungere un nuovo mostro all'array e aggiungere il peso al peso totale - questo può essere facilmente esteso durante il runtime se lo desideri (quindi, non importa fare modifiche al codice, non hai nemmeno bisogno per riavviare il programma per aggiungere un mostro (supponendo che il resto del programma lo consenta)).

classe mostro:

Avere una variabile int peso per ogni mostro.

Se i pesi sono 1,2 e 7, le rispettive probabilità saranno 10%, 20% e 70% (calcolato come 100*x/(1+2+7)).

Globali:

Random rand = new Random(); 
int totalMonsterWeight; 
Monster[] monsters; // set this up somewhere 

inizializzazione peso globale:

totalMonsterWeight = 0; 
for (Monster monster: monsters) 
    totalMonsterWeight += monster.getWeight(); 

funzione Get-mostro:

public Monster getMonster() 
{ 
    int weight = rand.nextInt(totalMonsterWeight); 
    for (Monster monster: monsters) 
    if ((weight -= monster.getWeight()) < 0) 
     return monster.getClass().newInstance(); 
} 

Quanto sopra è un modo pigro (probabilmente non il modo migliore) per restituire una nuova istanza durante ogni chiamata. Il modo giusto sta probabilmente usando un Factory pattern.

Problemi correlati