※記事の最後に、命令語と各ステージのクリア条件の和訳を掲載しています。

World of Goo」や「Little Inferno」など、独創的なヒットゲームを生み出してきた奇才 Kyle Gabler 氏の最新ゲーム。
コンピューターの演算処理を擬人化した、プログラミング・パズルゲームが登場しています。
Human Resource Machine」です。

パソコン(Steam)で昨年 10 月に公開されていたゲームで、iOS 版はその移植となります。
ゲームがコンピュータープログラムで作られているためか、プログラムをゲーム化しようという試みは過去何度も行われてきた訳ですが、その中でも最も「プログラミングらしいゲーム」と言えると思います。

様々な命令を実行させたい順番に並べて、条件を満たす数値や文字をアウトプットする内容で、前作の Little Inferno がただ物を燃やすだけのゲームだったのに、今回はロジック尽くめ。 まさに正反対と言えますね。

価格は 600 円。買い切りゲームなので課金・スタミナ・広告などは一切ありません。

Human Resource Machine

Human Resource Machine

「IN」と書かれたところから、主に数字が書かれた「リソース」が送られてきます。
これを条件に従って「OUT」と書かれたところに運べばステージクリアです。

最初に使える命令は「inbox」と「outbox」しかありません。
inbox は IN からリソースを受け取り、outbox は OUT にリソースを置きます。
最初のステージはリソースを3つ運べば良いので、この命令を3セット並べれば OK。

命令を並べて実行ボタンを押すと、社員くんがトコトコ歩いてリソースを運んでいきます。
もし間違ったリソースを送ったり、何もないのにリソースを取ろうとしたりすると、上司さんが怒ってエラーを出します。
何が悪かったかを言ってくれるので、それを元にデバッグ(修正)を行いましょう。
メッセージが英語なので文章は解りにくいのですが・・・ 置くべきリソースを表示してくれるので、だいたい解るはず。

次のステージに進むと「jump」という命令を使えるようになり、プログラムの実行順を変えられるようになります。
例えば「01 inbox、02 outbox、03 jump(01の前へ)」とすると、IN から OUT にリソースを運ぶ作業を延々と繰り返すようになります。

さらにゲームが進むと、床に枠が描かれているステージが登場。
ここには持っているリソースを「コピー」したり、置かれているリソースのコピーを持っていくことが出来ます。
さらに命令に「持っているリソースの数値と、枠に置かれているリソースの数値を足す」「枠にあるリソースの数値を1つ増やす」といったものも加わり、これらを使って数字を合算したり、数倍にして出力するステージなどが現れます。

「持っている数値が 0 なら指定の命令へ移動」といった状況を判断する命令語も登場し、これを使って「0 だけ OUT に運ぶ」といった作業も行えるようになります。

Human Resource Machine
※ミスったシーン。 上司が「それじゃないよ! コレだよ!」と指摘します。
「だったらお前がやれ!」と言いたくなるかもしれませんが、コンピューターさんは基本、融通が利きません・・・
クリアしたのに「Aha! Your solution works with ・・・」と言われた時は、今回は偶然クリア出来たけど、プログラムに欠陥があり、別の条件ではエラーになるケース。
リトライすると、改良しないと失敗するパターンが出て来ます。


Human Resource Machine
※上司をタップして「Give me an Example?」を選ぶと「こういう場合は、これをアウトプットするんだよ」という一例を教えてくれます。
条件がよく解らない時はこれを参考にしましょう。
ゲームが進むと目印のラベルを付けられるようになり、文字は手書きで書き込めます。


複雑そうなゲームですが、登場する命令はそんなに多くありません
IN のリソースを取る、OUT に置く、枠のリソースをコピー、数値の足し引き、数値を1つ増減、あとは命令の Jump 系。
Jump には「0 なら Jump」「マイナスなら Jump」もありますが、これで全てです。

よって覚えなければならない命令語は少ないのですが、しかし中盤からは「同じ数値の場合だけ出力」「数値を比べて小さい方を出力」といった条件も出て来ます。
しかしこのゲームに数の大小を調べる命令や不等号は存在しません。 ではどうするのか?

数が一致しているかどうかは、双方の数値を引いて、0 なら分岐する、というプログラムにすれば達成できます。
数の大小については、AからBを引いて、数値がマイナスでなければAが大きい、マイナスならBが大きいと判断できます。
ただしこの場合、AとBが同じ場合にバグる(Aが大きいと誤判定される)ので、それをチェックする部分を手前に入れておく必要があります。

このゲームのプログラムは微妙に不便で、そこを工夫で対処するのがパズルになっていると言えますね。
実際のプログラムはもっと多機能ですが、しかしこうした「普通にやるとうまく行かないけど、やり方次第で何とかなる」という状況は、実際のプログラミングでも良くある話です。

条件さえ達成できれば次に進めますが、各ステージには「プログラムの長さ」と「行程の多さ」による評価があります。
例えば、IN にある 1 , 2 , 3 , 4 のリソースを OUT に順番に運ぶ場合、「1を取る、OUT に運ぶ、2を取る、OUT に運ぶ、3を取る、OUT に運ぶ、4を取る、OUT に運ぶ」とすると8行のプログラムが必要ですが、「1を取る、枠にコピー、OUT に運ぶ、枠の数値を +1 してコピーを取る、OUT に運ぶに戻る」とすれば5行で済み、こちらの方が高評価になります。
現実のプログラムで言うと、データ量を節約できます。

ただ、後に述べた方法は「IN から取った数字を一旦枠に置く」という作業があるため、その分だけ行程が長くなり、行程の評価は最初の方が高くなります。
現実のプログラムで言うと、実行速度が速くなります。

ゲーム的には評価は単なるやり込み要素で、高評価を集めないと先に進めないということはないのですが、速くて短いプログラムを書けることはプログラマーの理想ですね。

Human Resource Machine
※後半になるとカッコ付きの数字が出て来ます。 これは「変数」で、その数字の枠の中にあるリソースの数値を、命令に利用できます。
ただ、これが出て来るのはステージ 29 から。 それ以前のステージで変数を使いたい場合、その替わりになるようなプログラムを工夫して作る必要があります。


Human Resource Machine
※クリア画面。 上の「サイズチャレンジ」が行数、下の「スピードチャレンジ」が行程数。 少ないほど優秀です。
一度に両方満たせないステージもあり、そういう場合はサイズ優先のプログラムと、スピード優先のプログラムで、別々にクリアする必要があります。


Human Resource Machine
※コーヒーブレイクに出て来る OL 三人衆。
Little Inferno と同じく、なにか意味深なバックストーリーがあるようですが、英語なのでよく解りません・・・
って言うか、英語が読めても多分漠然としか解らない。


これをやるとプログラムがどのように動いているのか、なぜバグが発生するのか、その辺がよく解ると思います。
そしてプログラミングがどれだけ面倒で、どうして良いプログラムを書ける人と書けない人がいるのかということも、何となく解るでしょう・・・

もちろんスマホのアプリも、こうした小さな命令の積み重ねで出来ています。
例えば、「ボタンが押されたかどうかチェック → 押されているなら弾を発射 → 弾があるなら座標を移動させる → 敵に当たったか判定 → 当たってるなら演出を表示してダメージ処理」みたいなのを並べていく訳ですね。
そして「弾の上限を設定してなかったからメチャメチャ連射できる」「敵に当たった弾を消してなかったからダメージが連続で入りまくる」みたいな誤動作が発生し、1つ1つデバッグしていく訳です。

このゲームのプログラムは旧式の形態ですが、ともあれプログラミングはロジックと工夫の積み重ね。
その工夫の部分の練習になるゲーム
として、これからソフトウェアやゲームに関わる仕事に就きたい人には、良い作品ではないかと思います。

もちろん普通に数学的パズルゲームとしても楽しめます。
メッセージが英語だし、解りやすい内容ではありませんが、グラフィックやインターフェイスは高クオリティーで、その辺はさすが World of GooLittle Inferno の作者さんのゲーム。
会社員がシステムの歯車のように働く様子には、ちょっとした風刺もあるかも?

パズル系が嫌いでない方にはオススメしたい作品ですね。

Human Resource Machine(iPhone 版、iTunes 起動)

Human Resource Machine(PC 版、Steam へ移動)

※Youtube 公式 PV




【 ちょこっと攻略:命令語とクリア条件の和訳 】

● 命令語

inbox:IN からリソースを取る
outbox:持っているリソースを OUT に置く
jump:指定の命令順に移動
copyfrom:指定した枠からリソースをコピーして取る
copyto:指定した枠へリソースをコピーする
add:持っている数値に指定の枠の数値を足す
sub:持っている数値から指定の枠の数値を引く
bump+:指定の枠の数値を1つ増やし、そのコピーを取る
bump-:指定の枠の数値を1つ減らし、そのコピーを取る
jump if zero:もし 0 であるなら jump を実行
jump if negative:もしマイナスであるなら jump を実行
[ 数値 ]:その数値の枠に入っているリソースの数字を対象とする

※文字同士で Sub した(引いた)場合、Aは1、Bは2、Cは3、Dは4・・・ という数値として扱われ、その計算結果を得られる。 ただし文字を足したり、文字と数字で計算しようとするとエラーになる。

● ステージクリア条件

:全てのリソースを OUT に運ぶ
:全てのリソースを3コマンドで OUT に運ぶ
:B U G の文字を OUT に運ぶ
:2つのリソースの順番を入れ替えて OUT に運ぶ。これを繰り返す
:(コーヒーブレイク)
:2つのリソースを足したものを OUT に運ぶ。これを繰り返す
:0 以外を OUT に運ぶ
:各リソースを3倍にして OUT に運ぶ
:0 だけ OUT に運ぶ
10:各リソースを8倍にして OUT に運ぶ
11:2つ目のリソースから1つ目のリソースを引いて OUT に運ぶ、次に1つ目のリソースから2つ目のリソースを引いて OUT に運ぶ。これを繰り返す
12:各リソースを 40 倍にして OUT に運ぶ
13:2つのリソースが同じなら、その1つを OUT に運ぶ。これを繰り返す
14:2つのリソースの大きい方を OUT に運ぶ。これを繰り返す
15:(コーヒーブレイク)
16:正の数はそのまま、負の数は正の数にして OUT に運ぶ
17:2つのリソースの正負が同じなら 0 を、違うなら 1 を OUT に運ぶ。これを繰り返す
18:(コーヒーブレイク)
19:各リソースを 0 までカウントダウン(カウントアップ)しながら OUT に運ぶ。5 なら 5,4,3,2,1,0 の順、-3 なら -3,-2,-1,0 の順
20:1つ目と2つ目のリソースの乗算を OUT に運ぶ。これを繰り返す
21:0 が出るまでの数列を合計して OUT に運ぶ。0 が連続している場合は 0 を OUT に運ぶ。これを繰り返す
22:各リソース以下のフィボナッチ数を OUT に運ぶ。フィボナッチ数は1つ前と2つ前の数字の合計の数列で 1,1,2,3,5,8,13,21,34・・・ よってリソースが 23 なら 1,1,2,3,5,8,13,21 を出力する
23:0 が出るまでの数列の中で、もっとも小さいものを OUT に運ぶ。これを繰り返す
24:1つ目の数値を2つ目の数値で割って、あまりを OUT に運ぶ。これを繰り返す
25:各リソースで1までカウントダウンした場合の数値の合計を出力する。4なら 4+3+2+1 で 10、5なら 5+4+3+2+1 で 15 となる
26:1つ目の数値を2つ目の数値で割った数を OUT に運ぶ。あまりは無視。これを繰り返す
27:(コーヒーブレイク)
28:1つ目~3つ目のリソースを数値の小さい順に OUT に運ぶ。これを繰り返す
29:各リソースの数字の枠にある文字を OUT に運ぶ。6なら6番目の枠の文字を出力する
30:各リソースの数字の枠から、0がある枠までの文字列を OUT に運ぶ。4番目の枠が T、5番目が H、6番目が 0 の状態で IN の数字が4の場合、T と H を出力
31:0 までの文字列を逆の順番で OUT に運ぶ。これを繰り返す
32:各リソースの文字が、場にいくつあるかを出力する
33:(コーヒーブレイク)
34:場にない文字のみを OUT に運ぶ
35:文字を1つずつ、ダブらないように OUT に運ぶ
36:0 で区切られた2つの文字列のうち、アルファベット順で速い方を OUT に運ぶ。一方の文字列が短い場合、文字が同じであるなら短い方が優先
37:文字と数値がペアになっている。 IN のリソースの数字の枠にある文字を出力し、次にその文字とペアの数字の枠にある文字を出力する。これをペアの数字がマイナスになるまで繰り返す
38:各リソースの数字をバラバラにして出力する。 63 なら 6 と 3 を OUT に運ぶ。 408 なら 4 と 0 と 8 を運ぶ
39:タイルに座標が書かれていて、リソースの数字が 6 なら、6 の枠がある横座標と縦座標を出力する。 この場合は 2 と 1 になる
40:各リソースの素因数分解を行う。12 なら 2,2,3。素因数分解を忘れているとクリアできない・・・ 難関だが未クリアでもエンディングには行ける
41:0 を区切りとする数列、及び文字列を、数の少ない順、及びアルファベット順で出力する