Gt、Lt【NandGame編】
はじめに
いつもブログをご覧いただきありがとうございます。
コーストFIRE中のIPUSIRONです😀
Gtレベル
Gtレベルのゴールは、マクロGTを実装することです。
マクロGTは、スタックから上から2つの値をPOPして(取り出して)比較します。最初の値が2番目の値より大きければ値-1(=0xFFFF)をPUSHし、そうでなければ0(=0x0000)をPUSHします。
最初のPOPで得られた値をv1、次のPOPで得られた値をv2とします。v1>v2なら-1、そうでないなら0をPUSHするということです。
![](https://akademeia.info/wp-content/uploads/2023/11/gt1.png)
Gtレベルを解く
マクロSUBを使うと、v2-v1の計算結果がスタックにPUSHされます。この計算結果を利用することを考えます。
ところで、マクロGTの(-1を出力する際の)条件式はv1>v2でした。SUBの計算結果「v2-v1」の形が得られるように、変形していきます。
v1>v2
0>v2-v1
v2-v1<0
このように変形できました。
このことから、SUBを呼び出した直後にスタックからPOPし、それが0未満であれば-1をPUSHすればよいのです。そして、それ以外の場合は0をPUSHします。
SUBとGTの条件式の違いについては、各レベルのExampleのスタックのイラストを見るとわかります(このスタックは下に伸びている)。beforeでは同一の状況ですが、SUBレベルのafterでは2(=5-3=v2-v1)がスタックにあります。一方、GTレベルのafterでは0になっており、これはつまり「v1>v2」以外のケースになっています。
![](https://akademeia.info/wp-content/uploads/2023/11/gt3.png)
![](https://akademeia.info/wp-content/uploads/2023/11/gt4.png)
Assembler Helpを見てください。Jump conditions系の命令を調べると、JLTがぴったりです。これを使えば、0未満かどうかで条件分岐できます。
![](https://akademeia.info/wp-content/uploads/2023/11/gt2.png)
以上を踏まえて、アセンブリーコードを実装します。基本的なロジックはEqレベルで実装したアセンブリコードと同様です。
SUB
POP_D
A = less_than
D ; JLT
D = 0
PUSH_D
A = skip
JMP
less_than:
D = -1
PUSH_D
skip:
このコードで正しいと思いましたが、テストすると次のエラーが発生します。
![](https://akademeia.info/wp-content/uploads/2023/11/gt6.png)
いちおう手動で次の3パターンをデバッグしても、期待する動作をしています。
[1]スタックに「POP 5⇒POP 3」をした状態なら、最終的に0
[2]スタックに「POP 5⇒POP 5」をした状態なら、最終的に0
[3]スタックに「POP 3⇒POP 5」をした状態なら、最終的に-1
一方、上記のコードにおいて、JLTではなくJGTに変更すると、なぜかテストにパスします。
※条件分岐のジャンプ先のラベル名を"goto"に変更しています。
SUB
POP_D
A = goto
D ; JGT
D = 0
PUSH_D
A = skip
JMP
goto:
D = -1
PUSH_D
skip:
![](https://akademeia.info/wp-content/uploads/2023/11/gt5.png)
手動デバッグで確かめてみました。スタックにPUSH 5⇒PUSH 3してから、コードをステップ実行すると、PUSH -1になり、イラストの結果(PUSH 0)と違います。
![](https://akademeia.info/wp-content/uploads/2023/11/gt7-1024x601.png)
原因がわかる方がいれば、是非ともDMください。
後になってから私の勘違いであることが判明するかもしれませんので、とりあえず先に進めます。
Ltレベル
Ltレベルのゴールは、マクロLTを実装することです。
マクロLTはスタックから2つの値を取り出して比較します。もし最初の値が2番目の値より小さければ値-1(=0xFFFF)をPUSHし、そうでなければ値0をPUSHします。
![](https://akademeia.info/wp-content/uploads/2023/11/lt1.png)
Ltレベルを解く
Gtレベルで説明したようにLtレベルの説明も疑わしいです。
ここではGtレベルの(等号なしの)逆バージョンに相当するものとして考えて解くことにします。
JGT命令をJLT命令に変えるだけです。
# Assembler code
SUB
POP_D
A = goto
D ; JLT
D = 0
PUSH_D
A = skip
JMP
goto:
D = -1
PUSH_D
skip:
![](https://akademeia.info/wp-content/uploads/2023/11/lt2.png)