2013-05-31 2 views
7

Предполагается, что я хочу создать игру. В начале игры игрок выберет монстра.Как написать алгоритм вероятности, который можно легко поддерживать?

Легко выбрать монстра.

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

И выбирает монстра несправедливо.

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

Проблема заключается в том, что, когда я добавляю новый монстр в игру, я должен изменить если-нибудь. Или я изменяю шанс выиграть GoldMonster до 0.2, мне нужно изменить все 0.1 на 0.2 . Это уродливо и нелегко поддерживать.

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

Как этот алгоритм вероятности может быть переработан так, что коды могут быть сохранены легко при добавлении нового монстра, и шансы на победу монстров отрегулированы?

+5

Выберите символ из случайной позиции строки 'GSSBBBBBBB'. Такая строка легко изменить. –

ответ

3

В основном, что сказал @Egor Skriptunoff. Это должно легко масштабироваться. Вы можете использовать коллекцию Class<Monster>, если вы не хотите использовать 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); 
} 

Вы могли бы, возможно, сделать перечисление Monsters множественного числа, и он указывает на Class<? extends Monster>, если вы все еще хотите, чтобы создать экземпляр классов монстра. Я просто попытался сделать пример более ясным.

+0

+1 для использования перечисления – monika

+1

Нет никаких признаков того, что это действительно произойдет, но если бы у вас было 1000 монстров, которые могли бы иметь вес в 1000-х годах, это могло бы стать довольно узким местом. – Dukeling

+1

Я думаю, вы имели в виду 'monster.size()' –

1

Я бы использовал общий вес, который увеличивается с каждым добавленным монстром.

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

По-прежнему требуется добавить if-statement при добавлении монстра. – Dukeling

+0

@ Dukeling В любом случае вам нужно что-то добавить, а одна строка - не столько для поддержания, я думаю. Иногда, имея более комплексное решение, вы можете скрыть то, что он действительно делает. ;) –

+1

Я думаю, что идеальным было бы решение, в котором вы можете добавить монстров без необходимости менять код вообще (так что это можно сделать во время выполнения), который [мой ответ] (http://stackoverflow.com/a/16858940/1711796). Не то чтобы я думаю, что кто-то обновляет игру во время выполнения, даже для MMO. – Dukeling

1

Основано на Peter's answer, просто более ремонтопригодным. Все, что вам нужно сделать, это добавить нового монстра в массив и добавить вес к общему весу - это может быть легко расширено, чтобы произойти во время выполнения, если вы хотите (таким образом, невзирая на изменение кода, вам даже не нужно перезапустить программу, чтобы добавить монстра (предполагая, что остальная часть вашей программы позволяет это)).

монстр класс:

У переменной int веса для каждого монстра.

Если весы составляют 1,2 и 7, соответствующие вероятности будут составлять 10%, 20% и 70% (рассчитанные как 100*x/(1+2+7)).

Глобалы:

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

Глобальная инициализация Вес:

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

функция Get-монстр:

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

Вышеприведенный способ (возможно, не самый лучший способ) вернуть новый экземпляр во время каждого вызова. Правильный путь, вероятно, с использованием Factory pattern.

Смежные вопросы