JavaScriptで箱入り娘を作る(2)の続きです。今回はスコアランキングを表示する機能を追加します。

逃亡者を公開処刑する鬼仕様?

これまでゲームのランキング表示はやってきましたが、今回は新たな要素を追加します。このゲームは途中でどうにもこうにもなくなりリロードしたくなることがあります。そのような場合、それもランキングに載せることにします。つまり逃亡者を公開処刑する鬼仕様とします。

JavaScriptでブラウザバックを記録する

ブラウザバックしたりリロードしたことはどうやれば記録することができるでしょうか?

beforeunloadイベントを利用します。ただしページにアクセスしてなにもしないでブラウザバックするとこのイベントは発生しないようです。今回のケースでいえばユーザーは[ゲーム開始]ボタンをクリックしたことを前提としているので、この部分は問題ありません。

サーバーにデータを送る

サーバーに送るデータですが、以下を送ります。

プレイヤー名
問題の最短手数
プレイヤーが実際に着手した手数
消費時間
ゲームをクリアできたかどうか?

gameStart関数の最後のほうで生成した問題をsolve関数を呼び出し、実際に問題を解くことで最短手数を取得し、これをグローバル変数に保存しておきます。

サーバーにデータをPOSTする処理を示します。

ゲームクリアしていないのにブラウザバックしたらサーバーにデータを送ります。ただしゲームを開始するまえにブラウザバックしたときはデータを送りたくないので time > 0 のときだけsendData関数を実行します。

同様にギブアップボタンをクリックしたときもデータを送ります。ただし一手も着手していない場合は送りません(やっていることはカンニンだから公開処刑の対象にしてもいいのだが・・・)。

サーバー側での処理

POSTされたデータをPHPで処理します。サーバー上のcsvファイルに追記しているだけです。

save-data.php

以下はサーバー上のcsvファイルのデータを文字列にして返す処理です。

get-data.php

ランキングを表示する

ランキングを表示する処理を示します。ランキングページに書かれているように、クリアまでの手数が少ないプレイヤーが上位、同じ手数であれば早く解いたプレイヤーが上位とし、上位20件、リタイアの直近の20件を表示することにします。

HTML部分

ランキングを表示するページを作成します。まずHTMLとCSSを示します。

ranking.css

Dataクラスの定義

サーバーから送られてきた文字列をランキングとして表示するデータに加工するためにDataクラスの定義します。コンストラクタに引数としてカンマ区切りの文字列が渡されるのでこれを分割して各メンバ変数に格納します。

地味に注意が必要な点として数値が入る変数には文字列としてではなくNumber型に変換してから代入しなければなりません。そうしないと後のソートの処理がうまくいきません。

ranking.js

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

ページが読み込まれたときの処理を示します。

getAllDatas関数を呼び出してサーバーから文字列を取得、そこからDataオブジェクトの配列を生成します。ここからランキング表示用のHTMLタグを生成してランキングを表示します。

サーバーから文字列を取得してDataオブジェクトの配列を生成する処理を示します。

ランキングを表示するHTMLの生成

Dataオブジェクトの配列からランキング表示用のHTMLを生成する処理を示します。

まず難易度順にDataを分けます。mapのKeyを問題の最短手数、ValueをDataの配列とします。Keyが存在しないならKeyを作り、あるならその配列へDataを追加します。

そのあと分類された各配列のなかのDataをゲームクリアできたものとできていないものにわけます。ゲームクリアできたものは手数が少ない順、同じであれば消費時間が少ない順にソートします。ゲームクリアできなかったものは単に順序を反転させます(直近のものが前にくるようにする)。そしてDataに格納されているデータをつかってHTMLを生成します。

getTimeText関数は秒数で与えられた引数を ◯分◯秒という形式の文字列に変換します。

オブジェクトの配列を複数のキーでソートする

sortEx関数はオブジェクトの配列をattrsに順にソートします。sortEx(clears, [‘NumberOfSteps’, ‘Time’])であればNumberOfStepsが小さい順にソートして、NumberOfStepsが同じならTimeが小さい順にソートします。