본문 바로가기
game theory

게임에서의 확률

by objet 2024. 10. 17.

 

게임에서 확률은 흔하게 쓰인다.
크리티컬 확률, 아이템 가챠, 스킬 발동률, 아이템 드랍률 등...

이런 확률을 구현하는 데 필요한 지식은 어떤 것이 있을까 찾아보다가 이 글을 쓰게 되었다.

 

난수

먼저, 게임에서 확률을 구현할 때 가장 핵심이 되는 것은 난수이다.

컴퓨터에서 쓰이는 난수란 엄밀히 말하면 난수가 아니다.
난수는 랜덤한 값을 의미하는데, 컴퓨터는 사람이 결정해놓은 규칙과 값을 토대로 계산하는 장치이기 때문에 순수하게 예측할 수 없는 난수를 생성할 수는 없다.

그래서 컴퓨터에서는 난수처럼 보이는 의사 난수(pseudo-random number)를 생성한다.

의사 난수는 일정하게 존재하는 수(예를 들어 시간)를 수학적 알고리즘으로 가공하여 난수를 흉내낸 수로, 초기값(seed)을 입력받아 seed값을 기반으로 일련의 유사 난수들을 생성한다.

시드가 어떤 값이냐를 기반으로 일련의 난수들이 만들어지기 때문에, 시드값이 같다면 같은 난수들이 나오게 할 수도 있다. 

따라서 난수를 생성할 때마다 시드값이 달라지게 하려면 그때그때 값이 달라지는(증가하는) 현재 시간의 값을 가져오든가, 물리적인 현상으로 인한 완전한 무작위 숫자를 이용해야 한다.

 

C의 rand() VS C++의 random 라이브러리

지금까지 C언어에서 우리가 흔히 난수를 구현하는 방법은 다음과 같았다.
seed값은 time.h의 time(NULL) 함수를 이용하여 현재 초를 가져왔다.
이럴 경우, 같은 시간대에 실행되는 프로그램은 동일한 난수들이 생성된다는 뜻이고,
제한된 범위 내의 난수를 생성하기 위해서 보통 rand() % 100와 같이 사용하는데, 이 방법은 균등하게 난수를 생성해내지 않는다.

또한 seed값을 바탕으로 난수들을 생성해내는 rand() 함수도 각 난수 간의 연관성이 높기 때문에 랜덤성이 떨어진다.

 

따라서 이런 점들을 보완하기 위해 C++에서는 고품질의 함수 라이브러리들이 존재한다.

C++의 <random> 라이브러리에서는 의사 난수 생성을 위한 다양한 함수들이 들어있는데, 그 중 집중해서 봐야 할 함수는 random_devicemt19937이다.

seed값을 생성할 때 random_device함수를 쓰게 되는데, 위 이미지에도 나와있듯 random_device는 비결정적(Non-deterministic)인 난수를 발생시킨다. 아까 컴퓨터는 결정적인 장치이기 때문에 미리 정해둔 알고리즘과 값으로 계산된다고 했는데, random_device는 하드웨어의 엔트로피 값을 기반으로 비결정적 난수를 생성하는 균일하게 분포된 정수 난수 생성기이다. 그러나 그만큼 난수열을 생성해내는 속도가 느려서, 이 함수는 seed값을 도출할 때 쓰는 것이 적합하다.

난수 생성 함수는 주로 mt19937함수를 사용하는데, 이미지 설명에도 나와있듯 Mersenne Twister라는 엔진을 기반으로 난수를 생성해내는 함수이다.

 

이후 이렇게 생성된 난수들을 우리가 원하는 범위의 값 내로 좁혀야 하는데, 이 때 분포를 이용한다.

 

 

 

흔히 쓰이는 수학적 지식은 이항 분포와 정규 분포가 있다.

 

 

▼ 참고한 글

더보기

 

'game theory' 카테고리의 다른 글

유도 미사일  (0) 2024.10.18