Undertale In Extremis
Projekt für Computerorganisation (Organização de Computadores). Undertale-ähnlicher Assembly Risc-V RPG-Kampfsimulator.
Universitätsprojekt (ORG 2026.1). Ein RPG-Kampfsimulator und Monte-Carlo-Engine, vollständig in RISC-V-Assembler geschrieben.
Der Aufbau
Ich habe eine RPG-Kampf-Engine von Grund auf in purem RISC-V-Assembler gebaut. Das Ziel war es, drei verschiedene KI-Zustandsmaschinen zu schreiben, sie in einen kopflosen Emulator zu werfen und 10.000 automatisierte Matches laufen zu lassen, um zu sehen, welche Strategie die Nase vorn hat.
Der Kampf dreht sich um eine strikte Aktionsökonomie. MP regeneriert langsam, kann aber mit bestimmten Fähigkeiten überladen werden.
| Fähigkeit | Kosten | Wirkung |
|---|---|---|
| Angriff | kostenlos | Würfelt einen 1W20. < 10 verfehlt, 10+ trifft, 20 kritischer Treffer für doppelten Schaden. |
| Verteidigen | kostenlos | Blockt eingehenden Schaden. Hohe Würfe lösen einen Konterangriff aus. |
| Absolute Zähigkeit | 20 MP | Umgeht den Würfelwurf für einen garantierten kritischen Treffer. |
| Seelenraub | kostenlos | Der Anwender erleidet 1–12 Rückstoßschaden, entzieht dem Gegner die gleiche Menge MP und erhält selbst das 4-Fache davon. Die einzige Möglichkeit, das 100-MP-Limit zu umgehen. |
| Finale Hinrichtung | 150 MP | Ein 800%-Schadensnuke. Schlägt fehl, wenn das Ziel über 50% KP hat. |
| Spiegelschild | 30 MP | Reflektiert den nächsten eingehenden Angriff zurück zum Angreifer. |
Die Kandidaten
Ich habe drei Bots geschrieben, jeder mit einem völlig anderen Gehirn:
Flowey (Das Chaos): Reiner RNG. Er bewertet nichts und würfelt einfach eine Zufallszahl, um seinen nächsten Zug zu wählen.
decision_random:
li a0, 6
call randomizer # wählt eine Zahl zwischen 1 und 6, das ist die ganze Strategie
j decision_end
Chara (Der Streber): Sie optimiert auf eine Combo: Seelenraub spammen, bis sie 150 MP erreicht, den Gegner unter 50% KP bringen und die Finale Hinrichtung einsetzen. Im Code heißt die Strategie auch smart, aber so ganz ist sie das nicht.
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 # preço do execute
blt t4, t6, decision_smart_my_mana_is_low # mp < 150? go farm
bge a2, t6, decision_smart_enemy_hp_high # enemy hp > 50? go bully
j decision_smart_i_can_kill # otherwise, 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 (Der Hard-Counter): Speziell gebaut, um Chara zu farmen. Er beobachtet sowohl seine eigenen KP als auch die MP-Leiste des Gegners. Wenn er unter 50 KP ist und der Gegner bei 150 MP sitzt, hebt er seinen Spiegelschild und lässt den Nuke zurückkommen. Außerhalb dieses Fensters mischt er Angriffe und Seelenraub und kann auch selbst die Finale Hinrichtung abfeuern, wenn die Bedingungen stimmen.
decision_troll_checks:
li t6, 50
ble t5, t6, decision_troll_check_enemy_mp # bin ich niedrig genug, um mir Sorgen zu machen?
j decision_troll_not_execute
decision_troll_check_enemy_mp:
li t6, 150
bge a3, t6, decision_troll_prepare_against_execute # ist der Gegner nah an 150 MP?
j decision_troll_not_execute
decision_troll_prepare_against_execute:
li a0, 6 # mirror shield
ret
Die Benchmark-Ergebnisse
Nach 10.000 Matches auf dem Terminal mit rars.jar, dem Jar aus dem RISC-V-Java-basierten Simulator RARS, kamen die Ergebnisse zurück.
| Charakter | Gewinnrate |
|---|---|
| Flowey | ~52% |
| Toby | ~29% |
| Chara | ~17% |
Die dümmste KI gewann die absolute Mehrheit der Spiele.
Charas 17% Gewinnrate offenbart das Problem mit starren, gierigen Combos. Um 150 MP zu erreichen, muss sie Rückstoßschaden von Seelenraub in Kauf nehmen. Oft hält Toby einfach seinen Schild hoch, und Charas Skript zwingt sie, weiter ihre eigene Gesundheit zu entleeren, bis sie sich buchstäblich selbst tötet, bevor sie überhaupt ihr Ultimate wirken kann.
Tobys 29% kommen daher, dass er Chara erfolgreich ködert. Gegen Flowey ist das eine andere Geschichte: Die Schildbedingung erfordert, dass der Gegner nahe an 150 MP ist, und Flowey baut nie gezielt darauf hin. Der Counter wird nie ausgelöst, also spielt Toby einfach sein Standardspiel aus Angriffen und Seelenraub, was ihm keinen wirklichen Vorteil gegenüber dem Chaos verschafft.
Flowey gewann 52% der Zeit, weil keine Strategie zu haben unmöglich konsistent gegenlesbar ist. Er nimmt nie Rückstoßschaden, um einen großen Spielzug vorzubereiten; er wirft einfach durch Zufall hochwertige Aktionen raus. Es stellt sich heraus: Wenn deine gesamte Codebasis darauf beruht, das Verhalten des Gegners vorherzusagen, verlierst du automatisch gegen einen Gegner, der Dinge ohne Grund tut.
Ist das tatsächlich überraschend?
Wahrscheinlich nicht. Dass zufällige Agenten deterministische dominieren, ist ein gut dokumentiertes Ergebnis in Strategiesimulationen.
Eine Citadel-Simulation, auf die ich in einer Studiengruppe gestoßen bin, zeigte dasselbe Muster: Einige Strategien schlugen konsistent Zufall, andere wurden von ihm zermalmt, und wieder andere besiegten bestimmte Gegner, verloren aber gegen andere. Die Schere-Stein-Papier-Dynamik war da, aber der Zufall behauptete sich dennoch gegen die meisten.
Der Unterschied ist, dass in einer reichhaltigeren Umgebung (mehr Strategien, mehr Entscheidungsvariablen, mehr Wege für einen intelligenten Agenten, einen zufälligen auszunutzen) die Ergebnisse tendenziell stärker streuen. Eine gut abgestimmte deterministische Strategie kann sich einen zuverlässigen Vorteil verschaffen, wenn der Aktionsraum ihr genug bietet, damit zu arbeiten.
Hier tut er das wahrscheinlich nicht. Mit nur sechs möglichen Aktionen und einem Kampfsystem, in dem ein einziger glücklicher kritischer Treffer das Match unabhängig von der Strategie beenden kann, ist die Lücke zwischen Charas sorgfältiger Planung und Floweys zufälligem Knöpfchenhämmern einfach nicht so groß. Charas Combo erfordert mehrere Runden Vorbereitung, und der RNG hat reichlich Gelegenheit, sie zu töten, bevor sie dort ankommt. Der Aktionsraum ist möglicherweise einfach zu klein und zu schwankungsanfällig, als dass eine gierige Strategie konsistent besser abschneiden könnte als Chaos.
Mit anderen Worten: Dass Flowey gewinnt, ist weniger eine Erkenntnis als vielmehr eine Designeinschränkung. Eine klügere Chara würde ein klügeres Spiel brauchen, um sich zu beweisen.
Warum diese Zahlen nicht vollständig zuverlässig sind
Bevor Schlussfolgerungen aus dem Benchmark gezogen werden, gibt es einige strukturelle Verzerrungen, die es wert sind, anerkannt zu werden.
Die Matchups sind nicht isoliert. Beide Spieler bekommen jede Runde eine zufällig zugewiesene Strategie, was bedeutet, dass die Gewinnraten Aggregate über alle möglichen Paarungen sind, keine sauberen 1v1-Statistiken. Floweys 52% beinhalten Matches, in denen Flowey gegen einen anderen Flowey kämpfte, und in denen musste einer von ihnen gewinnen. Um tatsächlich zu wissen, ob Chara Toby schlägt oder ob Flowey alle gleichermaßen schlägt, müsste man das Matchup fixieren und jede Paarung separat laufen lassen.
Die Zugreihenfolge wird nie rotiert. Spieler 1 zieht immer zuerst. In einem System, in dem ein einziger kritischer Treffer ein Match beenden kann, ist der erste Zug ein echter Vorteil. Die Ergebnisse berücksichtigen dies überhaupt nicht.
Der RNG ist ein benutzerdefinierter Xorshift, der mit der Systemzeit geseedet wird. Er funktioniert gut genug für ein Universitätsprojekt, aber es ist kein statistisch validierter Generator. Wenn die Verteilung der Ausgaben über die 6 möglichen Aktionen ungleichmäßig ist, sind Floweys Ergebnisse direkt betroffen, da seine gesamte Strategie nur darin besteht, diese Funktion aufzurufen.
Der Aktionsraum ist sehr klein. Sechs mögliche Aktionen bedeuten, dass jede Strategie nur begrenzten Spielraum hat, um sich vom Chaos abzuheben. In einem tieferen System wäre Charas Combo möglicherweise schwerer zu unterbrechen, oder es gäbe Erholungsoptionen, die die Kosten ihres Aufbaus reduzieren. Hier ist das Spiel gerade so bestrafend, dass ihr Rückstoßschaden oft den Lauf beendet, bevor die Auszahlung eintrifft.
Chara war wahrscheinlich nicht gut genug designt. Ihre Strategie hat kein defensives Rückfallnetz. Wenn die Combo-Bedingungen nicht erfüllt sind und sie schweren Schaden nimmt, farmt sie trotzdem weiter MP. Eine robustere Version würde unterhalb einer bestimmten KP-Schwelle in einen Überlebensmodus wechseln, was ihre Zahlen wahrscheinlich deutlich verbessern würde.
Die Ergebnisse sind in ihrer Tendenz interessant, sollten aber als Momentaufnahme dieser spezifischen Konfiguration gelesen werden, nicht als allgemeine Aussage über Strategie vs. Zufälligkeit.
Zukünftige Forschung
Der offensichtliche nächste Schritt ist, komplett von RARS wegzukommen. Diese Version läuft auf einem Java-basierten RISC-V-Emulator, was eine harte Obergrenze für die Simulationsgeschwindigkeit setzt. Eine zweite Version, die auf echten kompilierten RISC-V mit Linux-Syscalls anstelle von RARS-Ecalls abzielt, sollte dramatisch schneller sein, was sehr wichtig wird, sobald die Matchzahl in die Millionen geht.
Jenseits der Leistung sind die interessanteren Richtungen auf der Designseite:
Mehr Spieler pro Match. Im Moment ist es immer 1v1. Das Hinzufügen eines dritten oder vierten Teilnehmers verändert die strategische Landschaft vollständig. Plötzlich muss eine Gegenstrategie berücksichtigen, von zwei Seiten gleichzeitig angegriffen zu werden, und reine Zufälligkeit wird schwerer aufrechtzuerhalten.
Maschinelles Lernen im Assembler. Die Idee ist, einen minimalen ML-Algorithmus direkt in RISC-V zu implementieren, der Matrixoperationen verwendet, damit ein Bot seine eigenen Gewichte basierend auf Match-Ergebnissen aktualisieren kann. Keine externen Bibliotheken, keine High-Level-Laufzeitumgebung, nur Integer-Matrix-Mathematik in Registern. Ob dies praktikabel oder nur eine interessante Qual der Implementierung ist, ist Teil des Reizes.
Mehr Strategien und eine tiefere Engine. Der aktuelle Aktionsraum ist zu klein, als dass eine Strategie sinnvoll vor dem Zufall davonziehen könnte. Mehr direkte Inspiration von World of Warcraft (Abklingzeiten, Ressourcenabwägungen, Positionierungseffekte, vielfältigere Fähigkeitsinteraktionen) würde gut designten Strategien tatsächlich Raum geben, sich gegenüber dem Chaos zu beweisen.
Die Benchmark-Infrastruktur ist bereits vorhanden. Der Engpass ist, dass das Spiel tief genug sein muss, um die Ergebnisse aussagekräftig zu machen.
Ausführen
Um den Assembler zu kompilieren und die Engine lokal auszuführen:
make simulate
