こんにちは。
今回は「A=B」というゲームをやってみます。
ゲーム紹介シリーズです。
Steamのおすすめに載っていて、説明欄を読んでみると「命令が1つしかないプログラミングゲームです」とあったので興味をひきました。
もともと580円ですが、セールで406円だったので買ってみました。
「A=B」とは
「A=B」は string1 = string2 (最も左にある string1 を string2 に置き換える) という命令しかないプログラミング言語を用いて、様々な課題を解いていくパズルゲームです。
このゲームにおける実行フローは、
1. 入力文字列の読み込み
2. 実行可能な最初の命令を上から下に向かって探していく
2.1 実行可能な命令がある場合、現在の文字列を置き換える
2.2 実行可能な命令がない場合、実行を終了して現在の文字列を出力する
となっているようです。
百聞は一見に如かずということで、実際に見てみましょう。
実際に遊んでみる
ゲームを起動するとこんな感じです。

1-1
最初の課題「1-1 AをBに」を開くと、

左上に課題の説明があります。
今回は、すべての a を b に置き換えれば良いようです。
右上は入力文字列と、目標とする文字列が表示されています。
右下はコードを書く部分です。
すでに a=b と書かれています。
では、実行してみましょう。

左下にはログが表示され、abc に a=b が適用され、bbc となったことがわかります。
そして、実行可能な命令が無くなったので、bbc が出力されています。
テストケースがいくつかあるようで、実行し続けていくと「Accepted.」と表示されました。

1-2
2つ目の課題では、すべての文字を大文字に置き換えます。

コードは以下で良さそうです。
a=A b=B c=C
実行すると、「Accepted.」となりました。

初めに説明した実行フローをもう少し具体的に言うと、コードの1行1行について入力文字列をループし、一通り終わったら次の行へ、と進んでいく、ということです。
つまり、例えばテストケースが abcabc であった場合、まず a=A を適用しながらループするので AbcAbc となります。
続いて b=B を適用するので ABcABc、そして c=C で ABCABC となり、実行できる命令が無くなったので終了、という感じです。
以降は悩んだ課題や新要素を取り上げて紹介します。
1-4
課題1-4では、連続した a を削除します。

入力文字列は最大で7文字とあるので、ごり押しで…
aaaaaaa= aaaaaa= aaaaa= aaaa= aaa= aa=
一応クリアはできますが、チャレンジ要素として「追加の目的」があり、今回はコードを2行以下に収める必要があるようです。

考えてみましょう。
最短の連続は aa なので、aa= で無に置き換える操作は必要そうです。
これだけでは、偶数個の連続は処理できますが、奇数個の連続は a が余ってしまいます。
そこで、aaa=aa とすることによって、aaaaa→aaaa のように偶数個の連続に変換することができます。
文字列には偶数個の連続しか残っていないので、最後に aa= を実行すれば解決です。
aaa=aa aa=
クリアできました。

1-6
課題1-6では、文字列中の a と b の数を比較して、多い方を出力します。

この記事には載せていませんがひとつ前の課題でソートを扱ったので、使うと予想できます。
一旦、ソートのために ba=ab を入れておきましょう。
数が多い方の文字を残したいので、ab= でa と b を対消滅させていきます。
最後に、1個だけ残すように aa=a や bb=b で数を減らしていけば、完成です。
ba=ab ab= aa=a bb=b
クリアです。追加の目的もクリアできてました。

この辺りから難しくなってきますが、同時に「A=B」という命令の可能性を感じてきました。
2-1
一応のストーリーとして、講義の課題としてこのプログラミング言語を提出しようとしているようですが、教授から「「helloworld」を出力できないならプログラミング言語ではない」と言われてしまいます。
そこで、新たな命令が追加されました。
string1=(return)string2 :string1 にマッチした場合、プログラムを直ちに終了し、string2 を出力する
つまり、a というテストケースに対して a=(return)helloworld とすることで helloworld を (少々無理矢理にも感じますが) 出力できる、ということです。
2-3
課題2-3では、入力文字列が3文字か判定します。
文字数の判定において a や b の区別があるのは扱いづらいので、b=a、c=a で a に統一することにします。
こうしてしまえば、4文字以上2文字以下で false、3文字で true を出力するようにすれば良いだけです。
ちなみに、左辺を無にすることによりどんな場合でも実行するようにできます。
b=a c=a aaaa=(return)false aaa=(return)true =(return)false

2-6
課題2-6では、両隣の文字と異なる文字が1文字だけの場合に true、そうでなければ false を出力します。
日本語が難しいですが、ある文字について、その両隣を見たときにその文字と同じかどうか判定し、入力文字列の各文字すべてで見たときに、「異なる」と判定されたものが1文字であったら true を出力します。
具体的に言うと…
aabcc の場合、1文字目の a は隣が a なので「同じ」、2文字目の a は隣が a と b なので「同じ」となりますが、3文字目の b は隣が a と c なので「異なる」と判定されます。4、5文字目は「同じ」判定になるので、「異なる」判定の文字が1つしかないことなります。よって、このテストケースでは true です。
babbcc の場合、1文字目の b と2文字目の a が「異なる」判定になるので、「異なる」判定が2文字あり false になります。
さらに言ってしまえば、2個以上連続している文字が「同じ」判定になり、孤立した文字が「異なる」判定になるので…
孤立した文字が1文字だけのとき true、そうれなければ false を出力すれば良い
ということになります。
それではこれをどう判定するか考えます。
まずは、2個以上連続した文字は消せるので、1-4 でやったように、
aaa=aa aa=
他の文字についても然りです。
しかし、例えば ccaaac のような場合、aaa を消してしまうと最後に孤立している c が降りてきて、ccc となってしまいます。
こうなると、ccc も消せるので最終的に無になり、本来 true を出力すべきものが false と判定されてしまいます。
これを回避するために、aa=o のように別の文字を挟み、後ろの文字と連続しないようにします。
最後に o= を実行して挟んだ文字を消すことにより、孤立した文字だけを残すことができます。
続いて孤立した文字が1文字だけかどうか判定しますが、これは 2-3 でやったやり方を参考にすれば良いです。
aa=(return)false a=(return)true =(return)false
のようにすれば1文字の時だけ true を出力できますが、aa=o と干渉してしまいます。
そこで、a=x、b=x、c=x のように変換しておけば、
xx=(return)false x=(return)true =(return)false
と書けるので干渉しなくなります。
以上で完成です。
まとめると、
aaa=aa aa=o bbb=bb bb=o ccc=cc cc=o a=x b=x c=x o= xx=(return)false x=(return)true =(return)false
クリアです。追加の目的も達成してました。

まとめ
以上、「A=B」の紹介をしました。
ぶつ切りで申し訳ありませんが、だんだん難しくなってきたので一旦ここまでとします。
かなり骨太なパズルゲームなので、長いこと遊べるのではないかと思います。
以前に紹介した「ABI-DOS」をやっているときの感覚を思い出しました。
今ならワンコインで買えますので、皆さんもぜひやってみてください。
最後まで読んでいただいてありがとうございました。また次回。