当サイトの一部ページには、アフィリエイト・アドセンス・アソシエイト・プロモーション広告を掲載しています。

Amazonのアソシエイトとして、Security Akademeiaは適格販売により収入を得ています。

広告配信等の詳細については、プライバシーポリシーページに掲載しています。

消費者庁が、2023年10月1日から施行する景品表示法の規制対象(通称:ステマ規制)にならないよう、配慮して記事を作成しています。もし問題のある表現がありましたら、問い合わせページよりご連絡ください。

参考:令和5年10月1日からステルスマーケティングは景品表示法違反となります。 | 消費者庁

Gt、Lt【NandGame編】

はじめに

いつもブログをご覧いただきありがとうございます。

セミリタイア・ミジンコのIPUSIRONです😀

IPUSIRONのプロフィールを見る

Gtレベル

Gtレベルのゴールは、マクロGTを実装することです。

マクロGTは、スタックから上から2つの値をPOPして(取り出して)比較します。最初の値が2番目の値より大きければ値-1(=0xFFFF)をPUSHし、そうでなければ0(=0x0000)をPUSHします。

最初のPOPで得られた値をv1、次のPOPで得られた値をv2とします。v1>v2なら-1、そうでないなら0をPUSHするということです。

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」以外のケースになっています。

Assembler Helpを見てください。Jump conditions系の命令を調べると、JLTがぴったりです。これを使えば、0未満かどうかで条件分岐できます。

以上を踏まえて、アセンブリーコードを実装します。基本的なロジックはEqレベルで実装したアセンブリコードと同様です。

SUB
POP_D
A = less_than
D ; JLT
D = 0
PUSH_D
A = skip
JMP
less_than:
D = -1
PUSH_D
skip:

このコードで正しいと思いましたが、テストすると次のエラーが発生します。

いちおう手動で次の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:

手動デバッグで確かめてみました。スタックにPUSH 5⇒PUSH 3してから、コードをステップ実行すると、PUSH -1になり、イラストの結果(PUSH 0)と違います。

原因がわかる方がいれば、是非ともDMください。
後になってから私の勘違いであることが判明するかもしれませんので、とりあえず先に進めます。

Ltレベル

Ltレベルのゴールは、マクロLTを実装することです。

マクロLTはスタックから2つの値を取り出して比較します。もし最初の値が2番目の値より小さければ値-1(=0xFFFF)をPUSHし、そうでなければ値0をPUSHします。

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: