난수 생성에서 "너무"행운 / 불행 줄무늬를 피하려면 어떻게해야합니까?


30

나는 현재 플레이어가 다루는 피해에 항상 0.8과 1.2 사이의 임의의 요소가 곱해지는 멀티 플레이어 전투 시스템을 다루고 있습니다.

이론적으로, 무작위 RNG는 결국 같은 횟수를 여러 번 산출 할 수 있습니다 ( 테트리스 딜레마 참조 ). 이로 인해 플레이어는 항상 매우 높은 데미지를 입히고 다른 플레이어는 항상 매우 낮은 데미지를 입히게됩니다.

이런 일이 일어나지 않도록하려면 어떻게해야합니까? 반복을 피하는 데있어 RNG가 다른 RNG보다 우수합니까?


어떻게 작동하는지 모르겠습니다. 물론 모든 x가 큰 x1, x2, x3, x4의 시퀀스를 얻게됩니다. 그래도 랜덤하지 않습니까?
공산주의 오리

답변:


26

사전 설정된 데미지 결과 목록과 셔플 링을 통해 Tetris와 같은 방식으로 해결할 수 있습니다.

플레이어가 선형 분포로 0.8x에서 1.2x의 피해를 입을 것이라는 것을 알고 있다고 가정 해 봅시다. [0.8, 0.9, 1.0, 1.1, 1.2] 목록을 작성하십시오. 무작위로 섞어서 예를 들어 [1.2, 1.0, 0.8, 0.9, 1.1]이됩니다.

플레이어가 처음으로 피해를 입히면 1.2 배가됩니다. 그런 다음 1x. 그런 다음 등을 1.1x로 설정하십시오. 배열이 비어있는 경우에만 새 배열을 생성하고 섞어 야합니다.

실제로는 한 번에 4 개 이상의 배열로이 작업을 수행 할 수 있습니다 (예 : [0.8,0.8,0.8,0.8,0.9,0.9,0.9,0.9, ...]로 시작). 그렇지 않으면 시퀀스 기간이 짧아서 플레이어가 다음 히트가 "좋은지"여부를 알 수 있습니다. ( 드래곤 퀘스트 IX의 Hoimi 테이블 에서와 같이 전투에 더 많은 전략을 추가 할 수는 있지만 , 사람들은 치유 횟수를보고 조사하는 방법을 알아내어 드문 드롭을 보장합니다.)


3
좀 더 무작위로 만들려면 항상 목록의 절반을 임의의 숫자로, 나머지 절반은 (2-x)로 계산하여 평균을 정확하게 얻을 수 있습니다.
Adam

2
@Adam :이 방법은 실제로이 특정 예제에서만 작동합니다. 만약 당신이 멀티 플라이어를 손상시키기보다는 테트리스 조각을 다루고 있다면, 2-S 블록은 무엇입니까?

6
이를위한 일반적인 용어는 일종의 시스템으로 "임의의 교체없이"입니다. 주사위 대신에 카드 한 벌을 사용하는 것과 비슷합니다.
Kylotan

더 나은, 당신은 절반의 숫자를 할 수있는 정말 무작위, 절반 만이 규칙에 따라의.
o0 '.

1
그래도 로컬 배포가 전역 배포와 유사하지 않을 수 있습니다. 이것이 바로 질문이 원하지 않는 것입니다. "정말 임의"라는 용어는 모호한 의사 수학입니다. 원하는 통계 속성을 더 많이 정의할수록 의도와 게임 디자인이 더 명확 해집니다.

5

실제로이 작업을 수행 하는 코드를 작성 했습니다 . 그것의 요지는 불행한 줄무늬를 교정하기 위해 통계를 사용하고 있습니다. 이를 수행하는 방법은 이벤트가 발생한 횟수를 추적하고이를 사용하여 PRNG에 의해 생성 된 수를 바이어스하는 것입니다.

먼저, 이벤트 비율을 어떻게 추적합니까? 이 작업을 수행하는 순진한 방법은 메모리에 생성 된 모든 숫자를 유지하고 평균을내는 것입니다. 약간의 생각 후에 나는 다음을 생각해 냈습니다 (기본적으로 누적 이동 평균입니다 ).

다음 PRNG 샘플을 가져옵니다 (샘플이> = 0.5 인 경우 처리).

Values: 0.1, 0.5, 0.9, 0.4, 0.8
Events: 0  , 1  , 1  , 0  , 1
Percentage: 60%

각 값은 최종 결과의 1/5에 기여합니다. 다른 방법으로 살펴 보자.

Values: 0.1, 0.5
Events: 0  , 1

공지 그 0값의 50 %에 기여하고 1기여 값의 50 %. 약간 더 나아 가기 :

Values: [0.1, 0.5], 0.9
Events: [0  , 1  ], 1

이제 첫 번째 값은 값의 66 %와 마지막 33 %에 기여합니다. 우리는 기본적으로 이것을 다음 프로세스로 분리 할 수 ​​있습니다.

result = // 0 or 1 depending on the result of the event that was just generated
new_samples = samples + 1

average = (average * samples / new_samples) + (result * 1 / new_samples)
// Essentially:
average = (average * samples / new_samples) + (result / new_samples)

// You might want to limit this to, say, 100.
// Leaving it to carry on increasing can lead to unfairness
// if the game draws on forever.
samples = new_samples

이제 PRNG에서 샘플링 한 값의 결과를 편향시켜야합니다. 여기서 RTS의 랜덤 한 양의 손상과 비교할 때 훨씬 쉬울 것입니다. '나에게 일어난 일'이기 때문에 설명하기 어려울 것입니다. 평균이 낮을 경우 이벤트 발생 가능성을 높이고 비자 수반해야 함을 의미합니다. 몇 가지 예

average = 0.1
desired = 0.5
corrected_chance = 83%

average = 0.2
desired = 0.5
corrected_chance = 71%

average = 0.5
desired = 0.5
corrected_change = 50%

이제 나에게 발생한 것은 첫 번째 예에서 83 %가 "0.5에서 0.5"(즉, "0.5에서 0.5 + 0.1")에 불과했습니다. 무작위 이벤트 용어로 다음 중 하나를 의미합니다.

procced = (sample * 0.6) > 0.1
// or
procced = (sample * 0.6) <= 0.5

따라서 이벤트를 생성하려면 기본적으로 다음 코드를 사용하십시오.

total = average + desired
sample = rng_sample() * total // where the RNG provides a value between 0 and 1
procced = sample <= desired

따라서 요점에 넣은 코드를 얻습니다. 나는이 모든 것이 무작위 피해 사례 시나리오에서 사용될 수 있다고 확신하지만, 그 사실을 알아내는 데 시간이 걸리지 않았습니다.

면책 조항 : 이것은 모든 가정에서 얻은 통계이며, 현장에서 교육을받지 못했습니다. 내 단위 테스트는 통과합니다.


0.1과 0.9 값이 모두 0 이벤트를 유발하기 때문에 첫 번째 예제에서 오류처럼 보입니다. 그러나 기본적으로 누적 이동 평균 ( en.wikipedia.org/wiki/Moving_average#Cumulative_moving_average )을 유지하고 그에 따라 수정하는 것을 설명합니다. 한 가지 위험은 각 결과가 이전 결과와 크게 역의 상관 관계가 있지만이 상관 관계는 시간이 지남에 따라 감소한다는 것입니다.
Kylotan

1
나는 대신 '누수 적분기'시스템을 사용하도록 이것을 변경하려고 유혹합니다 : 평균은 0.5로 초기화되고 샘플을 세는 대신 증가하지 않는 임의의 상수 값 (예 : 10, 20, 50 또는 100)을 선택합니다. . 그런 다음 두 개의 후속 값 사이의 상관 관계는 발전기 사용 전체에서 일정합니다. 상수 값을 조정할 수도 있습니다. 값이 클수록 수정 속도가 느리고 무작위성이 더 높습니다.
Kylotan

@Kylotan 감사합니다. 이름을 제공해 주셔서 감사합니다. 나는 당신이 당신의 두 번째 의견과 정확히 무엇을 의미하는지 잘 모르겠습니다. 아마도 새로운 대답을 제공 할 수 있습니까?
Jonathan Dickinson

그것은 매우 영리하며 배열의 제한이 없습니다. Kylotan의 제안을 이해합니다.이 제안 samples은 처음부터 최대 값 (이 경우 100) 으로 초기화하는 것입니다 . 그렇게하면 RNG가 안정화되는 데 99 번의 반복이 필요하지 않습니다. 어느 쪽이든,이 방법으로 볼 수있는 단점은 공정성을 보장 하지 않고 단순히 평균을 일정하게 유지한다는 것입니다.
사용자가 찾을 수 없음

@jSepia-사실, 당신은 여전히 ​​공정성 / 불공정성을 얻을 수 있지만 균형 잡힌 달리기 (일반적으로)가 뒤 따릅니다. 예를 들어 단위 테스트에서 100 개의 비프로 시저를 '강제'하고 실제 샘플을 수행 할 때 ~ 60 개의 procs가 발생했습니다. 영향을받지 않는 상황에서 (코드를 보면) 일반적으로 50 % 프로세스는 최악의 경우 어느 방향 으로든 2/3의 실행을 봅니다. 그러나 한 선수는 다른 선수를 물리 치기 위해 달리기를 할 수 있습니다. 보다 공정하게 편향시키기를 원한다면 : total = (average / 2) + desired.
Jonathan Dickinson

3

당신이 요구하는 것은 실제로 비선형 분포 인 대부분의 PRNG와 반대입니다. 1.0x 이상의 모든 것이 어떤 종류의 "치명적 히트"라고 가정 할 때, 매 라운드마다 치명타를 입을 확률은 X만큼 올라갈 때까지 말하십시오. 그런 다음 각 라운드마다 두 번의 롤을 수행합니다. 하나는 치명타를 결정하고 다른 하나는 실제 크기를 결정합니다.


1
이것은 내가 취하는 일반적인 접근법입니다. RNG의 균일 한 분포를 사용하지만 변환하십시오. 또한 RNG의 출력을 최근 이력을 기반으로 다시 조정하는 사용자 정의 배포에 대한 입력으로 사용할 수 있습니다. 즉, 출력의 편차를 강제로 지정하여 사람의 인식 용어에서 "보다 무작위"로 보이도록 할 수 있습니다.
Michael

3
사실 이런 걸 않는 MMO 알고,하지만 당신은 때까지 치명타 가능성은 실제로 당신이 하나를 얻을 때마다 증가 하지 않는 한, 그것은 매우 낮은 값으로 재설정 얻을. 이것은 플레이어에게 매우 만족스러운 드문 줄이 생깁니다.
coderanger

좋은 alg, 길고 건조한 주문과 같은 소리는 항상 실망 스럽지만 미친 치명적인 줄무늬로 이어지지는 않습니다.
Michael

2
이를 수정하면 비선형 분포가 필요하지 않으며, 짧은 시간 순차 분포의 부분 집합이 분포 자체와 동일한 속성을 갖기 만하면됩니다.

이것은 블리자드 게임이 그렇게하는 방법이며, 워크래프트 3 이후로 적어도
dreta

2

Sid Meier는 GDC 2010에서이 주제와 문명 게임에 대해 훌륭한 연설을했습니다. 나중에 링크를 찾아 붙여 넣으려고합니다. 본질적으로-인식 된 무작위성은 실제 무작위성과 동일하지 않습니다. 상황을 공평하게하려면 이전 결과를 분석하고 플레이어 심리에주의를 기울여야합니다.

모든 비용으로 불운의 줄무늬를 피하십시오 (이전 두 턴이 운이 좋지 않으면 다음 번 운이 보장되어야 함). 플레이어는 항상 AI 상대보다 운이 좋아야합니다.


0

변속 바이어스 사용

01rb0

전체 분포는 다음 공식으로 편향됩니다.

rexp(b)

b1b0

이 숫자를 사용하여 원하는 범위로 적절하게 조정하십시오.

플레이어가 호의적으로 굴릴 때마다 편견에서 빼십시오. 플레이어가 불리하게 굴릴 때마다 편견을 더하십시오. 변경된 양은 롤이 얼마나 바람직하지 않은지 또는 균일 한 양 (또는 조합)인지에 따라 조정될 수 있습니다. 원하는 느낌에 맞게 특정 값을 조정해야합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.