Undertale In Extremis
TeX

Undertale In Extremis

コンピュータ構成(Organização de Computadores)のプロジェクト。Undertale風のアセンブリRisc-V RPGバトルシミュレーター。

大学プロジェクト(ORG 2026.1)。RISC-Vアセンブリで完全に記述されたRPG戦闘シミュレーターおよびモンテカルロエンジン。

セットアップ

私は生のRISC-VアセンブリでRPG戦闘エンジンをゼロから構築しました。目標は、3つの異なるAIステートマシンを書き、それらをヘッドレスエミュレーターに投入し、10,000回の自動マッチを実行してどの戦略が勝つかを確認することでした。

戦闘は厳格なアクション経済性を中心に展開します。MPはゆっくり回復しますが、特定のスキルを使用して過充電することができます。

スキル コスト 効果
攻撃 無料 1d20をロール。< 10でミス、10+でヒット、20でクリティカル(2倍ダメージ)。
防御 無料 受けるダメージをブロック。高いロールでカウンター攻撃を発動。
絶対根性 20 MP ダイスを回避し、確定クリティカルヒットを保証。
魂吸収 無料 術者は1~12の反動ダメージを受け、敵のMPから同量を吸収し、自身はその4倍を得る。100 MP上限を突破する唯一の方法。
最終処刑 150 MP 800%ダメージの核攻撃。ターゲットのHPが50%以上の場合は失敗。
鏡の盾 30 MP 次の攻撃を反射して攻撃者に返す。

contenders

私は3つのボットを書き、それぞれ全く異なる頭脳を持たせました:

Flowey(混沌): 純粋なRNG。何も評価せず、ランダムな数字をロールして次の行動を選びます。

decision_random:
  li a0, 6
  call randomizer  # 1から6の数字を選ぶ、それが戦略の全て
  j decision_end

Chara(努力家): 彼女は1つのコンボに最適化します:魂吸収を連打して150 MPに達し、敵のHPを50%以下に削り、最終処刑を放ちます。コード内ではこの戦略はsmartとも名付けられていますが、実際はそれほど賢くありません。

decision_smart:
  # 私はこの戦略を書きました
  # これは魂吸収を使ってexecuteを使えるようになるまで続ける戦略です
  # ただし、そのためには生き残り、敵のHPを50%まで減らす必要もあります
  # 死なずに
  ...
  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バーの両方を監視します。自分が50 HP以下で敵が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

ベンチマーク結果

RISC-V JavaベースシミュレーターRARSのjarであるrars.jarを使用してTerminal上で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つの可能なアクションと、戦略に関係なく1回の幸運なクリティカルで試合が終わる可能性がある戦闘システムでは、Charaの慎重な計画とFloweyのランダムなボタン連打の差はそれほど大きくありません。Charaのコンボは数ターンのセットアップを必要とし、RNGは彼女がそこに到達する前に彼女を殺す十分な機会があります。アクションスペースが小さすぎ、変動が大きすぎるため、貪欲な戦略が混沌を一貫して上回ることができないのかもしれません。

言い換えれば:Floweyの勝利は発見というよりも設計上の制約です。より賢いCharaは、それを証明するためにより賢いゲームを必要とするでしょう。

なぜこれらの数字が完全に信頼できないのか

ベンチマークから結論を導き出す前に、認めるべきいくつかの構造的バイアスがあります。

マッチアップは分離されていません。 両プレイヤーは各マッチでランダムに割り当てられた戦略を得るため、勝率はすべての可能なペアリングの集計であり、クリーンな1対1の統計ではありません。Floweyの52%には、Floweyが別のFloweyと戦ったマッチが含まれており、その場合どちらかが勝たなければなりませんでした。CharaがTobyに勝つのか、Floweyが全員に均等に勝つのかを実際に知るには、マッチアップを固定し、各ペアリングを個別に実行する必要があります。

ターン順序は決してローテーションされません。 プレイヤー1が常に先手です。1回のクリティカルで試合が終わるシステムでは、先手は本当の優位性です。結果はこれを全く考慮していません。

RNGはシステム時刻からシードされたカスタムxorshiftです。 大学プロジェクトとしては十分に機能しますが、統計的に検証されたジェネレーターではありません。6つの可能なアクション間で出力の分布が不均等な場合、Floweyの戦略全体がその関数を呼び出すだけなので、Floweyの結果に直接影響します。

アクションスペースは非常に小さいです。 6つの可能なアクションでは、どの戦略も混沌から差別化する余地が限られています。より深いシステムでは、Charaのコンボを妨害するのが難しくなるか、セットアップのコストを削減する回復オプションがあるかもしれません。ここでは、ゲームは彼女の反動ダメージがペイオフが到着する前にランを終わらせることが多いほど、ちょうど罰するように設計されています。

Charaはおそらく十分に設計されていませんでした。 彼女の戦略には防御的なフォールバックがありません。コンボ条件が満たされておらず、彼女が大きなダメージを受けている場合、彼女はとにかくMPをファームし続けます。より堅牢なバージョンは、特定のHPしきい値を下回ったときに生存モードに切り替えるでしょう。これにより、彼女の数字は意味のある形で改善される可能性があります。

結果は方向性として興味深いものですが、戦略対ランダム性に関する一般的な声明ではなく、この特定の構成のスナップショットとして読まれるべきです。

今後の研究

明らかな次のステップは、RARSから完全に離れることです。このバージョンはJavaベースのRISC-Vエミュレーター上で動作し、シミュレーション速度にハードな上限を課します。RARSのecallsの代わりにLinuxシステムコールを使用した実際のコンパイル済みRISC-Vをターゲットとする2番目のバージョンは、劇的に高速になるはずであり、これはマッチ数が数百万に達し始めると非常に重要になります。

パフォーマンス以外では、より興味深い方向性は設計面にあります:

1マッチあたりのプレイヤー数を増やす。 現在は常に1対1です。3人目または4人目の参加者を追加すると、戦略的状況が完全に変わります。突然、カウンター戦略は2方向からの攻撃を同時に考慮する必要があり、純粋なランダム性は持続が難しくなります。

アセンブリ内での機械学習。 アイデアは、RISC-V内で直接最小限のMLアルゴリズムを実装し、マトリックス演算を使用してボットがマッチ結果に基づいて自身の重みを更新できるようにすることです。外部ライブラリも高レベルランタイムもなく、レジスタ内の整数マトリックス演算のみです。これが実用的か、単に実装するのが興味深い苦痛かは、魅力の一部です。

より多くの戦略とより深いエンジン。 現在のアクションスペースは、どの戦略もランダムから意味のある形で抜け出すには小さすぎます。World of Warcraftからより直接的なインスピレーションを得る(クールダウン、リソースのトレードオフ、ポジショニング効果、より多様なスキル相互作用)ことで、適切に設計された戦略が混沌に対して実際に実力を証明する余地が生まれます。

ベンチマークインフラはすでに整っています。ボトルネックは、結果を意味のあるものにするのに十分な深さを持つゲームです。

実行方法

アセンブリをコンパイルしてエンジンをローカルで実行するには:

make simulate