人生

やっていきましょう

874日目

先日のギミックを応用させた新たな数字パズルを作った。アイデア自体はそれほど複雑ではなかったが、変数管理が難しく問題なく機能しているという確信が持てていない。

今回自分が作ったパズルは自分がやっていたオンラインゲームのミニゲームを参考にして作った。その内容は、0~9のまでの数を三桁入力して、ヒントを頼りにそれぞれの数の位置と値がすべて正しくなるように調整していくというゲームである。

ヒントというのは数値の入力後に出力される情報である。入力した数が、それに対応する答えの数値と値も位置も一致している場合は〇、値は一致しているが位置が一致していない場合は△、値も位置も一致していない場合は×を出力する。

たとえば答えとなる数値が303である場合、自分が114と入力したとすると1,1,4が3,0,3に対していずれも一致しないので〇を0、△を0、×を3つ出力する。また113と入力した場合、1,1,は対応しないが3が一の位の3と対応するので〇を1、△を0、×を2出力する。051を入力した際には、0が303の十の位と一致するが一の位とは一致しないので、〇を0、△を1、×を2出力する。

この〇と△と×を頼りに正しい数値を導くというゲームなのだが、はじめこのゲームがどのような処理によって行われているのかまるで分からなかった。特に位置と数値の判別方法のイメージがつきにくく、こうすれば良いとイメージできても実際どのように処理することができるかを考えると混乱した。そのため実現は困難に思えたが、どうにかその骨格を形にすることができた。

まずはじめに3桁の数字を各々管理する変数A,B,Cを用意する。それぞれに対し乱数0~9を代入し答えとなる値を定める。つぎにプレイヤーに3桁の数字を入力させる。そして入力した数値を一旦変数Oに預ける。このOから百の位、十の位、一の位をそれぞれ抽出してP,Q,Rに代入する。この抽出方法を考えるのが難しかったが、PはOを実数計算を用いて100で割ることで小数点以下を取り除くことで求まり、QはPを実数計算を用いて10で割ったあと10*Pを減算することで求まり、RはOから100P+10Rを減算することによって求まった(例えば456から値をそれぞれ取り出す場合、456を実数計算によって100で割った値は4、456を実数計算によってで10で割った45から4*10を引いた値が5、456から4*100+5*10を引いた値が6である)。

これらが終わったのちに、自分が入力した数値と答えが一致しているかどうかを判別する。条件として、まず【入力した百の位】の値が【答えとなる数の百の位】の値と一致しているかどうかを判別する。一致している場合は数の値と位置が一致しているということなので〇の数を管理する変数に1を加算する。一致していない場合は次の判定を行う。次の条件は【入力した百の位】の値が、【答えとなる数の十の位】もしくは【答えとなる数の一の位】と一致しているかどうかを判定する。ここでどれかが一致していれば、数の値は一致しているが、位置が一致していないということなので△の数を管理する変数に1を加算、いずれも一致していなければ数の値も位置も一致していないということなので×の数を管理する変数に1を加算する。これを同様に【入力した十の位】、【入力した一の位】に対して行う。

この部分を開発することに相当苦労した。はじめ自分は【入力した@の位】の値が【答えとなる@の位】の値と一致するかどうかではなく、【答えとなる@の位】が【入力した@の位】と一致するかどうかを判定するというまったく逆のことを行っていた。どちらでも結局は同じことだろうと思っていたからだ、しかしこの部分を反対にしていたことにより、どこか判定が狂ってしまっているということが分かった。

ほとんどの場合では正しい判定を出力する。しかしある数字になると判定がおかしくなる。具体的には〇が2つ、△が1つ、×が0というような状態になる時がある。本来ならば〇が2つならば×が1つでないとおかしいのだが、こうした結果を1度ばかりでなく何度も出力していた。

この問題の解決が開発の最も難しいところだったが、しばらく開発から離れてふと気が付いたことがあった。それは判定がおかしくなるのは決まって数値が【重複】するときだった。例えば969という値が答えであって、自分が960という数値を入力するとき、当時の判定に従えば、一の位に注目すると969の9は960の0と一致しないため次の判定に移るが、969の9は百の位である960の9と一致するため△を出力する、という処理が行われた。したがって重複があってそのうちのひとつが答えとして正しければ、必ず△を出力してしまうことになる。

この問題の解決法が判定の主体と対象を逆転させた、【入力した@の位】の値が【答えとなる@の位】の値と一致するかどうかを判定する、というものである。これにより重複が仮に生じたとしても、判定は自分が入力した値と一致しているかどうかだけを確認するので、重複の影響は一切受けない。その結果△とならずにちゃんと×を出力するようになった。

最後に加算された〇、△、×の数を集計する。その結果を変数を文章上に表すことのできる特殊文字を利用して文章で結果を表示する。そのとき〇が3つに達していたらクリア、達していなければ失敗の文章を出力する。いずれにせよ一回まわした際に入力回数管理の変数に1を加算し、〇、△、×に対して初期化を行う。

とにかく今回は心労がひどかった。残すギミックはあと2つだが、これ以上複雑で難しいギミックは作りたくないと思った。おそらく残りは自分で手軽に作れるものを作ると思う。