hrxdev
한국어

#1 컴파일러가 지키는 결정론적 코어

· Nick

아직 볼만한 것이 없어서, 첫 번째 글은 아무도 보지 못할 부분인 시뮬레이션 코어에 대해 씁니다. 이 게임은 초당 20틱으로 최대 1,000명의 수감자와 직원을 돌리고, 누가 왜 그랬는지 설명할 수 있어야 합니다. 같은 입력이 언제나 같은 월드를 만들 때에만 가능한 일입니다. 저는 이것을 첫날부터 기계가 확인하는 속성으로 만들기로 했습니다.

현재 상황

저는 첫 번째 마일스톤인 코어 골격을 진행하고 있습니다. 시뮬레이션은 Godot 코드가 전혀 없는 순수한 .NET 라이브러리이고, Godot 4 클라이언트는 아직 빈 3D 씬을 여는 것이 전부입니다. 월드 모델도, 타일도, 캐릭터도, 저장 기능도 없습니다. 1,000명이라는 예산은 목표일 뿐이며, 그 규모로는 아직 아무것도 측정하지 않았습니다.

틱

코어의 시간은 초당 20회의 정수 틱 카운트입니다. 부동소수점 시간은 없습니다. 한 틱은 세 단계로 진행됩니다. 외부 명령을 적용하고, 한 곳에 적힌 순서대로 시스템을 실행하고, 미뤄 둔 변경을 반영하면서 카운터를 올립니다. 틱 밖으로 오류가 새어 나오면 월드는 오류 상태로 표시되고 멈춥니다. 지금은 시스템 목록이 비어 있습니다. 첫 번째 시스템이 들어갈 자리를 만들어 두려고 루프부터 만들었습니다.

명령과 로그

월드는 명령으로만 바뀝니다. 명령은 안정적인 타입 ID와 직접 작성한 바이너리 인코딩을 가진 작은 레코드입니다. 각 명령에 대해 월드는 인코딩하고, 틱과 순번을 찍고, (읽기 전용으로) 검증하고, 로그에 기록한 뒤에야 적용합니다. 거부된 명령도 기록되므로 버그 제보에 도움이 될 것입니다. 시드와 로그가 있으면 실행을 정확히 재현할 수 있도록 하는 것이 목표입니다. 리플레이 파일 형식은 아직 작성하지 않았습니다.

난수

저는 난수 생성기(SplitMix64와 xoshiro256**)를 직접 작성했고, 표준 라이브러리의 Random은 코어에서 금지했습니다. 월드에는 시드에서 파생되어 월드 상태에 저장되는 네 개의 이름 붙은 스트림(명령, 욕구, AI, 이벤트)이 있어서, 저장되고 해시에도 포함됩니다. 순서가 영향을 주면 안 되는 작업에는 도메인, 엔티티, 틱을 기반으로 한 상태 없는 키 기반 생성기가 있습니다. 시드 42의 출력은 고정해 두었습니다. 사실상 이것이 리플레이 형식이기 때문입니다. 생성기를 바꾸면 기존 리플레이가 모두 깨집니다.

월드의 해시

순서에 민감한 작은 해셔가 시드, 틱, 난수 스트림, 명령 로그의 다이제스트를 64비트로 접어 넣습니다. 똑같아야 하는 두 번의 실행을 숫자 하나로 비교할 수 있습니다. 지금은 월드에 다른 것이 없어서 이 부분만 포함합니다. 실행 중 N틱마다 해시를 비교하는 것이 다음 단계입니다.

비결정성을 빌드 오류로 만들기

규칙을 기억하는 데 의존하고 싶지 않았습니다. 코어는 금지 API 분석기와 함께 빌드됩니다. 벽시계 시간, 시드 없는 난수, 무작위 GUID, 무작위화된 문자열 해시, 스레드와 병렬 도우미, SIMD, 문화권에 따라 달라지는 문자열 API는 모두 빌드를 실패시킵니다. 추가 검사에서는 가변 정적 상태가 없는지 확인하고, 빠져나간 것이 없는지 컴파일된 코드를 훑습니다. 제 컴퓨터는 소수점이 쉼표인 러시아어 로캘을 쓰기 때문에, 문화권에 의존하는 API를 금지할 이유가 충분했습니다.

그러다 한 걸음 더 나아가 표준 해시 컬렉션(Dictionary, HashSet 등)도 코어에서 금지했습니다. 순회 순서가 결과를 어긋나게 하는 전형적인 원인이기 때문입니다. 코어에서는 배열, 리스트, 그리고 순서가 문서화된 직접 만든 작은 컬렉션 두 개를 씁니다. 완벽하지는 않습니다. 제네릭 인터페이스를 통해 해시 컬렉션을 돌려주는 API는 여전히 빠져나올 수 있고, 보호의 일부는 테스트에서만 작동합니다.

만드는 방식

코드 주변의 도구도 자동화되어 있고, 같은 스크립트가 Windows와 macOS에서 실행됩니다. 전체적인 접근 방식은 만드는 방법에 있습니다.

다음

이 마일스톤에서 남은 것은 층이 있는 월드 모델, 저장과 리플레이 파일, 결정론 테스트, 그리고 벤치마크 기준선이 있는 헤드리스 시나리오 러너입니다. 그다음이 Godot 건설 화면입니다. 로드맵을 참고하세요.

← 모든 개발 일지