TECH 으로 돌아가기
TECH HACKER NEWS 오늘 7분 읽기 23 READS

팩토리오의 난수를 되짚다: 결정론적 게임 속 '무작위'를 예측하는 법

팩토리오의 난수를 되짚다: 결정론적 게임 속 '무작위'를 예측하는 법
SOURCE IMAGE · HACKER NEWS

자동화 게임 팩토리오(Factorio)의 확장팩 스페이스 에이지(Space Age)는 아이템과 건물에 '품질(quality)'이라는 개념을 새로 도입했다. 기본 아이템은 일반(common) 품질로 생산되지만, 제작 기계에 품질 모듈을 넣으면 더 높은 품질의 아이템이 나올 확률이 생긴다. 높은 품질의 아이템은 제작 속도가 빨라지고 모듈 효과가 강해지며 전신주 범위나 삽입기 속도가 향상되는 등 스탯이 개선된다. 개발진은 이 무작위성을 '결국 통계'라고 표현했다. 충분히 많은 양을 생산하면 관측되는 품질 분포가 기대 분포에 수렴한다는 뜻이다. 하지만 한 개발자 겸 리버스 엔지니어는 여기서 다른 질문을 던졌다. 애초에 완전히 결정론적으로 돌아가는 시뮬레이션 게임이 어떻게 무작위 메커니즘을 가질 수 있는가.

결정론적 게임의 난수

답은 컴퓨팅에서 흔히 쓰이는 의사난수생성기(PRNG)에 있다. PRNG는 겉보기에는 무작위처럼 보이는 수열을 만들어내지만 실제로는 결정론적 알고리즘이다. 보통은 그 내부를 신경 쓸 필요 없이 블랙박스처럼 난수를 뽑아 쓰면 그만이다. 그러나 알고리즘과 내부 상태를 알아낼 수 있다면 이야기가 달라진다. 게임 옆에서 동일한 계산을 나란히 돌려 향후 출력을 미리 계산할 수 있고, 그러면 어떤 제작 과정에서 품질 상승이 일어날지 같은 '미래의 무작위 사건'을 예측하게 된다. 결정론적이라는 성질이 곧 예측 가능성의 통로가 되는 셈이다.

필자는 먼저 팩토리오 포럼을 뒤졌다. 11년 전 같은 질문을 던진 글에서, 개발사 Wube의 전직 개발자 Cube가 boost 라이브러리의 생성기 중 가장 빠르다는 이유로 taus88을 선택했다고 밝힌 답변을 찾았다. taus88은 세 개의 선형 피드백 시프트 레지스터(LFSR) 결과를 XOR로 합치는 방식이다. 다만 그 글도 이미 오래된 것이었기에, 필자는 가장 정확한 출처인 게임 바이너리로 교차 검증에 나섰다.

바이너리로 확인한 taus88

팩토리오는 클로즈드 소스지만 개발진이 디버그 심볼이 담긴 .pdb 파일을 함께 배포한다. 덕분에 Ghidra(이후 Binary Ninja로 전환)로 잘 주석된 역컴파일 결과를 얻어 RandomGenerator 클래스와 getInt() 구현을 확인할 수 있었다. 원래 taus88 정의에 있던 상수들은 컴파일러의 상수 접기 최적화 때문에 거의 사라졌지만, 세 개의 시드를 저장하고 각 상태를 독립적으로 갱신한 뒤 셋을 XOR한다는 구조가 그대로 남아 있었다. 확신을 더하기 위해 필자는 두 구현을 파이썬으로 옮겨 심볼릭 연산 라이브러리 sympy로 한 스텝씩 전개했고, 96개 비트가 모두 동일하게 갱신됨을 확인했다. 손으로 하기엔 번거로운 검증을 도구로 매듭지은 것이다.

결론은 팩토리오가 세 개의 LFSR로 이뤄진 taus88을 쓴다는 것이었다. 흥미로운 점은 LFSR이 약한 PRNG로 잘 알려져 있으며, 문헌에서는 '자명하게 깨진다'고까지 서술된다는 사실이다. 그 약점의 뿌리는 선형성에 있다. LFSR은 단순 시프트만으로는 금세 0으로 수렴하고, 최하위 비트를 최상위로 되먹이면 n스텝마다 반복되는 뻔한 패턴이 된다. 그래서 피드백 비트를 중간 비트들에도 XOR로 끼워 넣는데, 이때 각 비트 상태가 이전 상태들의 선형 결합이 된다. 바로 이 선형성 때문에 관측만으로 내부 상태를 재구성할 수 있고, LFSR 단독으로는 암호학적으로 취약해진다.

수학적으로 LFSR은 F2 위의 다항식으로 모델링된다. 한 스텝은 현재 상태 다항식에 X를 곱하는 것과 같고, 여기에 원시(primitive) 피드백 다항식으로 나눈 나머지를 취하면 주기가 최대인 2ⁿ−1이 보장된다. 즉 피드백을 어느 비트에 삽입하느냐가 주기 길이를 좌우하며, 모든 구성이 동등하게 좋은 것은 아니다. 각 비트가 초기 비트들의 조합으로만 표현되고 xᵢ⊕xᵢ 같은 항은 상쇄되어 사라진다는 점이, 상태를 역산할 수 있는 선형대수적 근거가 된다. 이 글이 요구하는 배경지식이 기초 선형대수뿐이라고 밝힌 이유도 여기에 있다.

실무자에게 남는 함의와 한계

이 작업의 진짜 성과는 예측을 순수한 인게임 메커니즘만으로 구현했다는 데 있다. 외부 치트나 메모리 조작 없이 게임 내 요소로 난수 상태를 추적하고 조작해, 어느 제작에서 고품질이 나올지 미리 아는 방식이다. 다만 명확한 한계가 있다. 팩토리오 2.1은 RNG를 사용하는 방식을 바꿨고, 이 때문에 필자의 인게임 구현은 더 이상 동작하지 않는다. RNG 자체는 여전히 같은 taus88이므로 이론적 원리는 유효하지만, 실제 구현은 새 버전에 맞춰 다시 설계해야 한다.

실무 관점에서 이 사례가 주는 교훈은 두 가지다. 하나는 성능만 보고 고른 난수 생성기가 결정론적·재현 가능한 환경에서 예측 가능성이라는 부작용을 낳을 수 있다는 점이다. 게임의 멀티플레이 동기화나 리플레이처럼 결정론이 필수인 곳에서는 합리적 선택이지만, 결과의 비예측성이 중요하다면 LFSR 계열은 부적절하다. 다른 하나는 디버그 심볼을 함께 배포하면 역컴파일과 내부 동작 분석이 크게 쉬워진다는 사실이다. 결국 무엇을 무작위로 두고 무엇을 결정론으로 둘지, 그리고 어디까지 노출할지는 설계 시점에 의도적으로 판단해야 할 선택이라는 점을 이 분석은 잘 보여준다.

SOURCE · HACKER NEWS
원문 전체 보기 → https://gegell.github.io/posts/factorio-rng/
SHARE
NEXT · CHOOSE

변화를 읽었다면,
내가 만들 수익 구조를 고릅니다.

정보를 더 모으는 데서 멈추지 않고, 광고·외주·판매·중개·구독 중 내 상황에 맞는 출발점을 정해보세요.

21가지 수익 구조 살펴보기
처리 중...