JavaScriptで箱入り娘を作る(1)の続きです。今回はギブアップしたときに解を表示させる機能を追加します。

Statusクラスの定義

現在の盤面の状態を操作できるようにStatusクラスを定義します。

コンストラクタ

コンストラクタを示します。引数は操作後のarray2x2、手数、操作前のブロックがあった位置、移動方向です。

移動させたときにarray2x2の要素が変わってしまわないように引数として渡されたarray2x2のコピーをthis.Array2x2に格納しています。ここからRectangleオブジェクトの配列も生成しています。

また一度探索をした部分を何度も探索して無限ループに入りこまないようにarray2x2の要素をつなげて文字列にしたものをKeyにしています(異なるブロックでも同じ種類であれば同一局面とみなす)。

移動可能か?

引数で指定されたブロックを引数で指定された方向に移動可能かを調べる処理を示します。ここでは例えば左に移動させるのであればブロックの左側の座標をすべて取得し、1個以上の座標が存在し、そのすべてが’空’であれば移動可能であると判定しています。

移動させる

引数で指定されたブロックを引数で指定された方向に移動させる処理を示します。ここでは移動可能であればRectangle.RowとRectangle.Colの値を変更してStatus.Array2x2を更新しています。

Status.Array2x2を更新する処理を示します。

移動後の結果をすべて取得する

GetMoveResults関数は移動可能なすべてのブロックを移動させて新しいStatusオブジェクトの配列を返します。

2マス移動可能な場合もあるので1マス移動させたらさらに移動できるか試してみます。移動できたら移動後の状態を配列に格納し、すぐに移動前の状態に戻します。Status.Rectanglesに格納されているオブジェクトに対して4方向の移動を試すことで移動後のすべての結果を取得することができます。

最短手順を表示する

上で定義したStatusクラスをつかって最短手順を取得して表示します。

最短手順を取得する

最短手順を取得するには現在のarray2x2をStatusクラスのコンストラクタに渡して最初のStatusオブジェクトを生成しqueue(実は配列)に格納します。そのあと幅優先探索で移動可能なブロックを移動してできるパターンをすべて取得し、これまでに探索していないものであればqueueに追加してqueueが空になるまで処理を繰り返します。

途中で娘が出口に存在するパターンが見つかったら解が存在するということなので、そのときのStatusオブジェクトを変数lastに格納します。そしてlastを最初の状態にむけて遡りながら取得されたStatusオブジェクトをretsに追加していきます。最後にretsを反転させればどのブロックをどの方向に移動するかがわかるようになります。

解を表示する

ギブアップボタンをクリックしたときの処理を示します。solve関数が返したStatusオブジェクトの配列を順番にみていけばどの位置にあるブロックをどの方向に移動させればいいかがわかるのでそのとおりに移動させます。そして最後に娘を退場させます。