Unseen Fruit【Turing Complete編】
Unseen Fruitステージ
地球上でもっとも注目すべきものはフルーツです。クルーたちによると、とてもおいしいとのことです。そこで、食堂でフルーツの試食会を開催します。
しかし、同じフルーツを二度手に入れることは恥ずかしいと感じます。確実に同じフルーツを手に入れないようにしたいです。
ロボットを使ってフルーツをスキャンします。ベルトコンベアー上を定期的にスキャンして、フルーツが入ってくるかどうかをチェックします。同じ種類のフルーツが2回検出したら、すぐに操作パネルを回して押します。



ロボットの制御
出力バイトデータ | ロボットの動作 | 動作の意味 |
---|---|---|
0 | left | 左を向く。 |
1 | forward | 前に進む。 |
2 | right | 右を向く。 |
3 | enjoy | 待機(足踏み)する。 |
4 | action | 前方のオブジェクトを検知する。 ※何もなければ0が入力される。 |
5 | shoot | レーザーを撃つ。 |

ロボットをテスト操縦してみよう
Spacial Invasionステージと同様に、ロボットを操縦できます。
まずはキーボードからロボットを操縦して、ステージでフルーツがどういった風に流れるのかを確認してみましょう。
・左右キー・・・向きを変える。
・上キー・・・前進。
・[Enter]キー・・・待機(時間経過)。
・[Tab]キー・・・レーザーを発射。



何もしないとどうなるのかプログラムで確認する
手動でロボットを操縦して、同じフルーツが流れたとしても、ゲームオーバーになることはありませんでした。
プログラム操作時に同じフルーツが流れたときにどうなるのかを調べてみます。
次に示すプログラムは、その場から動かずに時間を経過させるプログラムです。
1 2 3 4 5 6 7 8 9 10 | const LEFT 0 const FORWARD 1 const RIGHT 2 const ENJOY 3 const ACTION 4 const SHOOT 5 label main ADDii ENJOY 0 OUTPUT IF_EQ REG0 REG0 main |
ベルトコンベアーから次々にフルーツが流れてきます。同じフルーツが左の出口から出ていっても特にライフが減ったり、ゲームオーバーになったりすることはありませんでした。

なお、プログラムを実行しようとしても反応がない場合は、一度Level mapに戻ってから、当ステージに入り直してください。
ステージの仕様
・右上の入り口からフルーツがベルトコンベアーに乗って流れてくる。そして、左上の出口から出ていく。
・フルーツの種類によって物体コードが違っている。
・ロボット用の作業部屋では、手前の隙間からベルトコンベアー上をチェックできる。action(物体調査)で目の前の物体の種類を識別する。
・ベルトコンベアー上をチェックする場所の右側に制御盤がある。右側を向けばよいだけ。
つまり、ボタンを押すには右側を向いてaction。
食堂でクルーと会話しよう【おまけ】
作業部屋の下の扉は開きません。
左側の壁は壊れかけており、レーザーで破壊できます。破壊したら壁に穴ができて、隣の食堂に移動できます。
食堂では、クルーたちが食事をしています。会話もできます。




牢獄からみんなを逃がそう【おまけ】
食堂室の下のドアから出ると、牢獄に入ります。ステージクリアには直接関係なく、おまけです。
制御盤を使って牢を開けると、警備員が怒って、ロボットをつかまえようと近づいてきます。
ロボットが捕まるとゲームオーバーです。ゲーム-オーバー後は牢獄から再開しますが、元のベルトコンベアーのあるフロアーに戻れます。



Unseen Fruitステージを解く
1:プログラムを設計する
プログラムの流れをざっくりと決めると、次のようになりました。
①監視場所に移動する。
②常に物体調査を実施する。
③もしフルーツを検知したら、記憶済みのフルーツであるかを調べる。
まだ記憶していないフルーツであれば、記録する。逆に一度記憶したフルーツであれば、制御盤を向いてボタンを押す。
以降のステップからプログラムを段階的に実装していきます。
2:定位置まで移動する処理を実装する
ベルトコンベアーを調べる位置(定位置と呼ぶことにする)まで、最短で移動します。
ベルトコンベアーの入り口から定位置までは距離があるので、すぐにフルーツが流れてきても、最初のフルーツが来るまでに定位置への移動が間に合います。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | const LEFT 0 const FORWARD 1 const RIGHT 2 const ENJOY 3 const ACTION 4 const SHOOT 5 # 定位置に移動. ADDii LEFT 0 OUTPUT ADDii FORWARD 0 OUTPUT ADDii LEFT 0 OUTPUT ADDii FORWARD 0 OUTPUT ADDii FORWARD 0 OUTPUT ADDii FORWARD 0 OUTPUT ADDii LEFT 0 OUTPUT ADDii FORWARD 0 OUTPUT ADDii RIGHT 0 OUTPUT ADDii FORWARD 0 OUTPUT ADDii FORWARD 0 OUTPUT |

3:監視処理を実装する
ベルトコンベアーの物体コードは92です。目の前を調べてこれ以外の物体コードであれば、ベルトコンベアー上に何か(ここではフルーツ)が乗っていると判断できます。
そのとき、RAMに登録された物体コード群と比較します。未登録であればRAMに登録して、監視に戻ります。登録済みであれば、右側を向いて、actionを実行します。
RAMから登録されたデータを全部取り出せたかどうかは、「RAMに登録したデータのカウンターを用意する」あるいは「取り出したデータが00hならもう存在しない」のどちらかで判定できます。ここでは前者のアプローチを採用します。
REG 1は目の前の物体コード、REG 2はRAMから取り出した物体コードです。
以上をまとめると、次のプログラムになりました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | const LEFT 0 const FORWARD 1 const RIGHT 2 const ENJOY 3 const ACTION 4 const SHOOT 5 const BELT_CONVEYOR 92 const NUM_STORE REG3 # RAMの登録データ数. # 定位置に移動. ADDii LEFT 0 OUTPUT ADDii FORWARD 0 OUTPUT ADDii LEFT 0 OUTPUT ADDii FORWARD 0 OUTPUT ADDii FORWARD 0 OUTPUT ADDii FORWARD 0 OUTPUT ADDii LEFT 0 OUTPUT ADDii FORWARD 0 OUTPUT ADDii RIGHT 0 OUTPUT ADDii FORWARD 0 OUTPUT ADDii FORWARD 0 OUTPUT # 監視処理. label monitor ADDii ACTION 0 OUTPUT ADDi INPUT 0 REG1 IF_NOT_EQi REG1 BELT_CONVEYOR ram_check IF_EQ REG0 REG0 monitor # 強制ジャンプ. # RAMに登録済みかをチェック. label ram_check XOR RAM RAM RAM # アクセスアドレスのゼロクリア. ADDi NUM_STORE 0 REG0 # REG 0は残りコード数. label check_1code IF_EQi REG0 0 regist_code LOAD _ _ REG2 IF_NOT_EQ REG1 REG2 next CALL control_panel _ _ IF_EQ REG0 REG0 monitor # 強制ジャンプ. label next ADDi RAM 1 RAM # アクセスアドレスをインクリメント. SUBi REG0 1 REG0 IF_EQ REG0 REG0 check_1code # 強制ジャンプ. label regist_code ADDi NUM_STORE 0 RAM # RAMのアドレスは0インデックスを考慮. SAVE REG1 _ _ ADDi NUM_STORE 1 NUM_STORE IF_EQ REG0 REG0 monitor # 強制ジャンプ. label control_panel ADDii RIGHT 0 OUTPUT ADDii ACTION 0 OUTPUT RET _ _ _ |

接尾が「i」「ii」なのか、4バイト命令になっているかに注意してください。
もしテストのパスしない場合、ロジックにミスがあるだけでなく、こうした文法ミスが影響している可能性があります。
高級言語であればコンパイラーが書式ミスを知らせてくれることもありますが、アセンブリー言語のような低級言語はミスすればプログラムが暴走するだけです。シミュレーターはテストが失敗するとエラーを知らせてくれますが、それはテストパターンとして期待する挙動をしないからです。こうしたテストがなければ、暴走した状態かどうかも人が判断しなければならないです。
4:テストする
同じフルーツが検出したら、コントロールパネルをactionします(押します)。1つでもそれが成功すればテスト成功です。
テストにパスすると、ステージクリアになります。

ただし、同じフルーツが連続が流れてきた場合にパスしたとしても、連続でなくても同じフルーツが流れてくれば、コントロールパネルを押さなければなりません。一度テストにパスしたからといって安心できないわけです。
※新しいフルーツが流れてくるたびに、アドレス00hのデータだけが書き換わるのではなく、どんどん追加されることを確認しなければなりません。
