前回は セグメント木をネタにゲーム を作りましたが、今回はフェニック木でゲームを作ります。クソゲー姉妹品 「セグ木が嫌ならFenwick木で殴ってやろうか?」です。ルールは前回と同じです。

フェニック木とは何か?

フェニック木 または Binary Indexed Tree (BIT) とは、部分和の計算と要素の更新の両方を効率的に行える木構造のことです。要素の更新と区間和の計算の両方が時間計算量 O(logN)で可能です。ピーター・フェニックにより提案されました。

セグメント木と比べると部分和の計算しかできない、部分和の計算も任意の区間ではなくA[0]からA[i]までという制限がありますが、セグ木よりも使用するノード数が少なく動作が軽いこと、任意の区間[a, b]の部分和であれば[0, b] – [0, a – 1]を計算すればよいことから使い勝手はよいと思われます。

以下はJavaScriptで書いたフェニック木のコードです。ノードを表すindexからその親と子のindexを求める処理が興味深いです。

HTML部分

ではさっそく作っていきましょう。最初にHTML部分を示します。

style.css

Gameクラスの定義

Gameクラスを定義します。最初にコンストラクタを示します。

index.js

フェニック木の更新処理

フェニック木を更新するための処理を示します。以下は配列のidx番目がxに更新されたときにフェニック木を更新するとともに表示されている値を変更するためのものです。

以下は配列のidx番目がxに更新されたときにフェニック木と表示を更新するものですが、一気におこなわず、待機時間をいれながら どのノードが更新されたのかが視覚的にわかるようにしながら更新するためのものです。

ユーザーが更新ボタンをクリックしたら更新すべき値でフェニック木と表示されている値を更新します。

お題を生成する処理

お題を生成する処理を示します。やっていることは お前もセグ木で殴ってやろうか? とほぼ同じです。

フェニック木と表示を初期化する処理

フェニック木と表示を初期化する処理を示します。お題を表す変数に格納されている値と現在の状態を示す値を同じにしているだけです。最後にこの値でフェニック木を初期化します。

正誤判定

正誤判定をする部分を示します。

まず区間和を取得する処理を示します。ここでは区間を被覆しているノードを拾い集めてその和を計算するとともにそのノードに相当する部分を色を変えて表示することでフェニック木でどのような処理が行われているのかがわかるようにしています。

Check関数はお題の区間和と実際の区間和がすべて一致するか調べ、合っていればステージクリアの処理を、合っていなければそのステージを最初からやり直させる処理をおこなっています。

ゲームの開始とリセット

ゲーム開始時の処理を示します。

ステージの初期状態に戻す処理を示します。

更新処理

時間の経過とともに残り時間を減算する処理と時間切れになったらゲームオーバー処理をおこなう処理を示します。

ゲームオーバー時の処理

ゲームオーバー時の処理を示します。スコアランキングにスコアを登録します。

サーバー側の処理とスコアランキングを表示させる処理はゲーム開始以降の処理 鳩でもわかるXORパズルをつくる(2)と同じなので省略します。

ページが読み込まれたときの処理

ページが読み込まれたときの処理を示します。Gameオブジェクトを生成してイベントリスナを追加してUpdate関数を呼び出しているだけです。レンジスライダーで効果音の音量をコントロールできるようにする処理はいつもと同じ処理です。