TIS生存報告

 さて気付けば今年も残り僅かになってきましたねというところで、多分来月は気も回らない題材なので一足先に、某アセンブラパズル「TIS-100」
 一応めげずに続けてるよ!報告というか、気付けば忘れてしまいそうではあるけれども一ヶ月に数問くらいのペースで、基本的に脳内エミュさえ出来れば画面はいらないゲームなので、寝床で考え事をしながらそのまま程良く疲れ果てて眠りに落ちる算段も含めつつ、大体考えが固まったところでさっとコーディングして答え合わせ、みたいな流れでやっております。それが綺麗に収まると一安心。

 しかし改めて考えると、およそ実用的かと問われるとちょっと返答に困りそうな特殊CPUの命令セットとメモリ(実行コード長)の制約。ただある種の非現実とも言える特定ルールに則って与えられた課題を解いていくという行為は、成る程これも何だかんだでゲームというものなのかと思ってみたりもして。
 特に、アセンブラの原始的な命令文でのコーディングとなると一見ギチギチの最適化の印象を与えがちだけれども、実際はその貧弱に過ぎる命令セットとコード長で問題文を解いていく為には、如何にして問題文・入出力データの処理を定型化・単純化するかという観点こそが重要となってくる。(まぁプログラミングというもの自体が本来そういう物だよねと言ってしまえばそうなんですが)、そこを見極めてロジックさえ組み上げてしまえば後のコーディングはただの確認作業だとすら。

 この点、これってプログラミングのロジカルな思考を鍛える教育素材として案外役に立ったりしないかと、一度若いのをこれで鍛えてみたらどうなるかとか内心思ったりもしておりますが(ぉ)。取っ付きの点であまりにも精神障壁の壁が高く分厚くそびえすぎて「ちょっとこの人何言ってるの」的に、流石に誰にも勧めることすら出来ておりません。
 そんなもんプログラミング実習で十分だと思われるかもしれないけど、やはり一つのポイントとして「ルールが特殊」な所から「それに見合った解を導き出す」行程が存在するのは大きいんじゃないかなと。ただでさえネットのご時世、コピペ参照し放題だし、既に発明されたアルゴリズムをなぞる知識運用だけでなく、条件と目的から解を導く思考部分にこそ注目したい。まぁ単純に数学スキルとかに近いのかもしれませんが(言っても自分、数学はドロップアウトしてましたが)。どうなんだろう。

 とか何とか書き散らして終わらせるつもりで居た訳ですが、まぁちょっと嫌な予感もしていたけれども案の定と申しますか、書こうとしたこのタイミングでまた再びSTACK MEMORYの面で躓いておりましたよ(苦笑)。いや今回は、無難なロジックを思い付いて程なく完成してそれでおしまいの筈が、無難どころかまたも平均スコア(CYCLE)の遥か下。命令数(INSTR)の山もまるでずれている(こちらは良スコア)ので、狙ってもいないのにまたギチギチコードになってしまったのかと。(>”SEQUENCE GAP INTERPOLATOR”)
 いや自分、別に高スコアが目的だとかそういう訳ではなく、まぁ最低限整ったコードに収めるくらいまではやりたくはなるけれども、1CYCLE,1INSTRを争うようなテクニックの追求がしたい訳ではない。
 むしろやっている皆々様も多分「一回やっておしまい」くらいのプレイが多いだろうし、だからこそスコア分布の山が一つの指標として表れてくる訳で、その平均に遠く及ばないスコアというのは余程自分がヘタレなのか明後日のロジックを書いているのか。ましてやそれがまだ少しなら「まぁ下手も打つ」くらいで済むかもしれないけれど、STACK MEMORYのステージでばかりこう度々この有様では、流石に「根本的に足りてない?」という疑念に苛まれてしまうというもの。
 この点、このTIS-100という仮想CPUは複数ノードを並列稼働させる分散・並列コーディングが最大の肝となるところで。如何せんSTACK MEMORYはその特性上、直列的なロジックになりがちなので、ノード配置からコード記述まで何か重大なテクニックが欠けているのか、あるいは根本的に考え方が間違っているのか。やはりそこを押さえなければとてもクリアしたとは言えないという悔いが残る。
(パズルゲームなので出回っている答えを入れれば解けてしまう、それが平均スコアとして出ているだけではないか?という見方もついしてしまいたくはなるものの、ただこのゲームに限ってはそこまでして解く理由が全く見当たらないというか。本当に解きたくて解く人以外やってないんじゃないかなぁ。)

 そんな訳で、実際苦し紛れ感の否めない汚いコードを綺麗な形に収められないものか、あるいは全く別のアプローチも無いのかも含めながら、あれやこれやと休日が災いして本来やろうとしてた事も放置して「こんな気分のまま切り替えられるか!」とばかりに再三足掻き続け、「もうこれが駄目なら諦めよう」と言い始めてから更に二・三回、「アカンこれ前回やったやつや」。
 まぁ先に書いたように、単なる手落ち以上の根本的な疑念があればこそ、なかなか諦めも着けられなかったというものですが。そういう「諦めの悪さ」のパラメータ値だけは無闇に高いので、、。

 そうこうしながら紙に書き出した数列の束を見ている内にふとティンと来たアルゴリズム。意外と組めそうだけど、でもこれって、うーん、まさか、、、?
 そう、そのまさかでした、
 「STACK MEMORYを使わない」

 「こんなのズルいじゃん!」って奴ですよ。これ見よがしのSTACK MEMORYの配置はまさかのトラップですか(スタックとしては使わず、通り道として使うだけ)
 まぁ普通にSTACK MEMORYを使ったロジックも形にはなったし、このステージの作者も案外それを正解のつもりで作ったのか、あるいは逃げの余地を残したのか。(追記:改めて振り返ると以前にもスタックを使わない面はあった。というかそこもハマってた。)
 しかしそんなものに惑わされず、数列処理のテクニックという点で手短な正解に辿り着いていたのが世の大多数の皆々様でありました。うん、ホントにこれマニアしかやってないよね(笑)。

 という訳で、無事に解けて平均スコアと同列に並んだ上に少し手直ししたら平均値の左にまでスコアが伸びたところで一安心。ひとまず疑念と不安も解消して一段落というものですよ。

 でもって、
 いつもグダグダ文章ばかりで具体的な物が無いと片手落ちとも思われるかなぁと。まぁパズルは自力で解くべきというスタンスも強い訳ですが、人のコードを参考にすることも悪いことではないからということで。今回たまにはということで晒してみます、以下ネタバレで。
 ちょっと汚い部分も残るコードなんで見苦しいですけどね。ソートは散々コード記述を試した物の中から比較的マシなのを抜粋。ホント見せられるものじゃないんですが。何やってんの?かも。あとコメントも無いコードは許しがたいがこの場合は致し方ないので、、。
*NEXUS17: “SEQUENCE GAP INTERPOLATOR”:数列の抜けを検出する
・ソートした列から抜けをスキャン(挿入ソート後)
・ソートした列から抜けをスキャン(バブルソートで逐次)
・数列の最小最大値と合計値の関係から抜けを算出する(即日微修正:冗長さは潰せてないけど)

 まぁちゃんとプレイしてるんだよアピールということで(笑)。