2013-05-31 5 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는 다음과 같이 말했습니다. 이것은 쉽게 확장되어야합니다. enum을 사용하지 않으려면 Class<Monster> 콜렉션을 사용할 수 있습니다.

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

enum을 사용하기 위해 +1 – monika

+1

이것이 실제로 일어날 것이라는 표시는 없지만, 1000s에서 가중치를 가질 수있는 1000s의 몬스터가 있다면 병목 현상이 될 수 있습니다. – 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 문을 추가해야합니다. – 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(); 

가져 오기 - 괴물 기능 :

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

위의 방법은 각 호출 중에 새 인스턴스를 반환하는 게으른 방법입니다 (아마도 최선의 방법은 아님). 올바른 방법은 아마도 Factory pattern을 사용하는 것입니다.