Undertale In Extremis
컴퓨터 구조(Organização de Computadores)를 위한 프로젝트. 언더테일 스타일의 RISC-V 어셈블리 RPG 전투 시뮬레이터.
대학교 프로젝트 (ORG 2026.1). RISC-V 어셈블리로 완전히 작성된 RPG 전투 시뮬레이터 및 몬테카를로 엔진.
설정
순수 RISC-V 어셈블리로 RPG 전투 엔진을 처음부터 구축했습니다. 목표는 세 가지 서로 다른 AI 상태 기계를 작성하고, 헤드리스 에뮬레이터에 넣은 후 10,000번의 자동 매치를 실행하여 어떤 전략이 가장 우수한지 확인하는 것이었습니다.
전투는 엄격한 행동 경제를 기반으로 합니다. MP는 천천히 재생되지만, 특정 스킬을 사용하여 과충전할 수 있습니다.
| 스킬 | 비용 | 효과 |
|---|---|---|
| 공격 | 무료 | 1d20을 굴립니다. < 10은 빗나감, 10+는 명중, 20은 치명타로 두 배 피해. |
| 방어 | 무료 | 들어오는 피해를 막습니다. 높은 굴림 시 반격을 실행합니다. |
| 절대 투지 | 20 MP | 주사위를 무시하고 확정 치명타를 가합니다. |
| 영혼 흡수 | 무료 | 시전자가 1~12의 반동 피해를 입고, 적의 MP에서 동일한 양을 흡수하며, 자신은 그 4배를 얻습니다. 100 MP 제한을 우회하는 유일한 방법입니다. |
| 최후의 집행 | 150 MP | 800% 피해를 주는 핵 공격입니다. 대상의 HP가 50% 이상이면 실패합니다. |
| 거울 방패 | 30 MP | 다음에 들어오는 공격을 공격자에게 반사합니다. |
참가자
각각 완전히 다른 두뇌를 가진 세 개의 봇을 작성했습니다:
Flowey (혼돈): 순수 RNG. 아무것도 평가하지 않고 무작위 숫자를 굴려 다음 행동을 선택합니다.
decision_random:
li a0, 6
call randomizer # 1에서 6 사이의 숫자를 선택합니다, 이것이 전체 전략입니다
j decision_end
Chara (열정맨): 하나의 콤보에 최적화합니다: 영혼 흡수를 150 MP에 도달할 때까지 난사하고, 적의 HP를 50% 미만으로 깎은 후 최후의 집행을 사용합니다. 코드에서는 이 전략을 스마트라고도 부르지만, 실제로는 그렇지 않습니다.
decision_smart:
# eu escrevi essa estrategia
# ela se consiste em usar roubo de alma até poder usar execute
# só que pra isso também precisamos sobreviver e diminuir a vida do inimigo pra 50%
# sem morrer
...
li t6, 150 # execute 가격
blt t4, t6, decision_smart_my_mana_is_low # mp < 150? 파밍하러 가기
bge a2, t6, decision_smart_enemy_hp_high # 적 hp > 50%? 괴롭히러 가기
j decision_smart_i_can_kill # 아니면, execute 실행
decision_smart_my_mana_is_low:
li a0, 4 # soul suck
decision_smart_enemy_hp_high:
li a0, 2 # absolute grit
decision_smart_i_can_kill:
li a0, 5 # final execution
Toby (하드 카운터): Chara를 파밍하기 위해 특별히 제작되었습니다. 자신의 HP와 적의 MP 막대를 모두 관찰합니다. 자신의 HP가 50 미만이고 적이 150 MP를 보유하고 있으면 거울 방패를 들어 핵 공격을 되돌려줍니다. 그 외의 상황에서는 공격과 영혼 흡수를 혼합하고, 조건이 맞으면 자신도 최후의 집행을 발사할 수 있습니다.
decision_troll_checks:
li t6, 50
ble t5, t6, decision_troll_check_enemy_mp # 내가 걱정할 정도로 낮은가?
j decision_troll_not_execute
decision_troll_check_enemy_mp:
li t6, 150
bge a3, t6, decision_troll_prepare_against_execute # 적이 150 mp에 가까운가?
j decision_troll_not_execute
decision_troll_prepare_against_execute:
li a0, 6 # mirror shield
ret
벤치마크 결과
rars.jar(RISC-V 자바 기반 시뮬레이터 RARS의 jar 파일)를 사용하여 터미널에서 10,000번의 매치를 실행한 결과는 다음과 같습니다.
| 캐릭터 | 승률 |
|---|---|
| Flowey | ~52% |
| Toby | ~29% |
| Chara | ~17% |
가장 멍청한 AI가 게임의 절대 다수를 승리했습니다.
Chara의 17% 승률은 경직되고 탐욕스러운 콤보의 문제점을 드러냅니다. 150 MP에 도달하려면 영혼 흡수의 반동 피해를 감수해야 합니다. Toby가 방패를 들어올리면, Chara의 스크립트는 궁극기를 시전하기도 전에 문자 그대로 스스로 죽을 때까지 자신의 체력을 계속 소모하도록 강제됩니다.
Toby의 29%는 Chara를 성공적으로 유인한 결과입니다. Flowey를 상대로는 다른 이야기입니다: 방패 조건은 적이 150 MP에 가까워야 하는데, Flowey는 의도적으로 그쪽으로 빌드업하지 않습니다. 카운터가 발동되지 않아 Toby는 기본 공격과 영혼 흡수 게임만 하게 되고, 이는 혼돈에 비해 실질적인 이점을 주지 못합니다.
Flowey가 52%를 승리한 이유는 전략이 없으면 일관되게 카운터 읽기가 불가능하기 때문입니다. 그는 거대한 플레이를 준비하려고 반동 피해를 입지 않습니다. 그저 우연히 고가치 움직임을 던질 뿐입니다. 전체 코드베이스가 적의 행동 예측에 의존한다면, 이유 없이 행동하는 적에게 자동으로 패배한다는 것이 밝혀졌습니다.
이것이 실제로 놀라운가요?
아마 아닐 것입니다. 결정론적 에이전트를 지배하는 무작위 에이전트는 전략 시뮬레이션에서 잘 문서화된 결과입니다.
스터디 그룹에서 접한 Citadel 시뮬레이션도 동일한 패턴을 보여주었습니다: 일부 전략은 무작위를 일관되게 이기고, 일부는 무작위에 의해 압도당했으며, 일부는 특정 상대를 이기지만 다른 상대에게는 패배했습니다. 가위바위보 역학이 존재했지만, 무작위는 여전히 대부분의 상대에게 자신의 입지를 유지했습니다.
차이점은 더 풍부한 환경(더 많은 전략, 더 많은 결정 변수, 똑똑한 에이전트가 무작위 에이전트를 이용할 수 있는 더 많은 방법)에서는 결과가 더 퍼지는 경향이 있다는 것입니다. 잘 조정된 결정론적 전략은 행동 공간이 충분히 활용할 수 있게 해준다면 신뢰할 수 있는 우위를 확보할 수 있습니다.
여기서는 아마 그렇지 않을 것입니다. 단 6개의 가능한 행동과 단 한 번의 운 좋은 치명타가 전략과 관계없이 매치를 끝낼 수 있는 전투 시스템에서, Chara의 신중한 계획과 Flowey의 무작위 버튼 난타 사이의 격차는 그렇게 크지 않습니다. Chara의 콤보는 여러 턴의 준비가 필요하며, RNG는 그녀가 도달하기 전에 죽일 충분한 기회를 가집니다. 행동 공간이 너무 작고 변동성이 커서 탐욕 전략이 혼돈을 일관되게 능가하기 어려울 수 있습니다.
다시 말해: Flowey의 승리는 발견이라기보다 설계 제약에 가깝습니다. 더 똑똑한 Chara는 자신을 증명하기 위해 더 똑똑한 게임이 필요할 것입니다.
이 숫자가 완전히 신뢰할 수 없는 이유
벤치마크에서 결론을 도출하기 전에 인정해야 할 몇 가지 구조적 편향이 있습니다.
매치업이 분리되지 않았습니다. 두 플레이어는 각 매치마다 무작위로 할당된 전략을 받습니다. 즉, 승률은 모든 가능한 페어링의 집계이며, 깔끔한 1v1 통계가 아닙니다. Flowey의 52%에는 Flowey가 다른 Flowey와 싸운 매치가 포함되며, 그중 하나는 반드시 승리해야 했습니다. Chara가 Toby를 이기는지, Flowey가 모든 사람을 동등하게 이기는지 실제로 알려면 매치업을 고정하고 각 페어링을 별도로 실행해야 합니다.
턴 순서가 변경되지 않았습니다. 플레이어 1이 항상 먼저 움직입니다. 단 한 번의 치명타가 매치를 끝낼 수 있는 시스템에서 선공은 실질적인 이점입니다. 결과는 이를 전혀 고려하지 않습니다.
RNG는 시스템 시간에서 시드된 커스텀 xorshift입니다. 대학교 프로젝트로는 충분히 잘 작동하지만, 통계적으로 검증된 생성기는 아닙니다. 6개의 가능한 행동에 걸쳐 출력 분포가 고르지 않다면, Flowey의 전체 전략이 해당 함수를 호출하는 것이기 때문에 Flowey의 결과에 직접적인 영향을 미칩니다.
행동 공간이 매우 작습니다. 6개의 가능한 행동은 어떤 전략도 혼돈과 차별화할 여지가 제한적임을 의미합니다. 더 깊은 시스템에서는 Chara의 콤보를 방해하기 더 어렵거나, 설정 비용을 줄이는 회복 옵션이 있을 수 있습니다. 여기서 게임은 그녀의 반동 피해가 보상이 도착하기 전에 실행을 종료시킬 만큼 충분히 가혹합니다.
Chara가 충분히 잘 설계되지 않았을 가능성이 높습니다. 그녀의 전략에는 방어적 대비책이 없습니다. 콤보 조건이 충족되지 않고 큰 피해를 입고 있을 때도 계속 MP를 파밍합니다. 더 견고한 버전은 특정 HP 임계값 이하에서 생존 모드로 전환할 것이며, 이는 그녀의 수치를 의미 있게 향상시킬 것입니다.
결과는 방향성 있게 흥미롭지만, 전략 대 무작위성에 대한 일반적인 진술이 아닌 이 특정 구성의 스냅샷으로 읽어야 합니다.
향후 연구
명백한 다음 단계는 RARS에서 완전히 벗어나는 것입니다. 이 버전은 자바 기반 RISC-V 에뮬레이터에서 실행되며, 시뮬레이션 속도에 하드 한계를 설정합니다. RARS ecalls 대신 Linux 시스템 콜을 사용하는 실제 컴파일된 RISC-V를 대상으로 하는 두 번째 버전은 매치 수가 수백만 개로 증가할 때 크게 중요해지는 극적으로 빠른 속도를 제공해야 합니다.
성능 외에도 더 흥미로운 방향은 설계 측면에 있습니다:
매치당 더 많은 플레이어. 현재는 항상 1v1입니다. 세 번째 또는 네 번째 참가자를 추가하면 전략적 환경이 완전히 바뀝니다. 갑자기 카운터 전략은 두 방향에서 동시에 공격받는 것을 고려해야 하며, 순수한 무작위성은 유지하기 어려워집니다.
어셈블리 내부의 머신 러닝. 아이디어는 RISC-V에서 직접 최소 ML 알고리즘을 구현하여, 매트릭스 연산을 통해 봇이 매치 결과에 따라 자체 가중치를 업데이트하도록 하는 것입니다. 외부 라이브러리 없이, 고수준 런타임 없이, 레지스터에서의 정수 매트릭스 수학만으로 말입니다. 이것이 실용적인지 아니면 단지 구현하기에 흥미로운 고통인지는 매력의 일부입니다.
더 많은 전략과 더 깊은 엔진. 현재 행동 공간은 어떤 전략이 무작위보다 의미 있게 앞서기에는 너무 작습니다. World of Warcraft(쿨다운, 자원 트레이드오프, 위치 효과, 더 다양한 스킬 상호작용)에서 더 직접적인 영감을 받으면 잘 설계된 전략이 혼돈 위에서 자신을 증명할 실제 여지를 제공할 것입니다.
벤치마크 인프라는 이미 갖춰져 있습니다. 병목 현상은 결과가 의미 있게 만드는 데 충분히 깊은 게임입니다.
실행 방법
어셈블리를 컴파일하고 엔진을 로컬에서 실행하려면:
make simulate
