パズドラ練習アプリ/スタミナ管理ツール作成

パズドラの練習アプリとスタミナ管理ツールを作成したのでご紹介します。
ブログメニューの倉庫のなかに保管しました。

倉庫 – パズドラ練習アプリ
倉庫 – パズドラスタミナ管理ツール

練習アプリはJavaScriptを勉強し始めた頃に作ったもので、今回はソースの見直し、余分な機能の削除、コンボエフェクト追加、Edit機能の改善(作り替え)などを行いました。ベースはできていたのですぐ終わるだろうと思っていたのですが、当時JavaScriptの本を読みながら動かすことだけを目標に作っていたせいで、至る所にコメント(「クロージャとは?」とか「あとで!」など)や自由過ぎるグローバル変数が記述されていてたいへんでした。大抵プログラムには複数のフラグが必要になるわけですが、ちゃんとまとめておかないと後々えらいことになるということを実感しました。

スタミナ管理ツールはできたてホヤホヤです。練習アプリの公開のついでに作ってみました。グラフの作成にはこれまでflotr2を使っていたのですが今回インタラクティブにしたくて初めてChart.jsを使いました。コーディング的にはどちらも同じような感じでしたが、インタラクティブに対応しているせいかChart.jsのほうが華やかでオシャレ度が高いと思いました。プラグインで拡張もできるみたいです。わたし的にはインタラクティブ性が欲しい時はChart.js、軽く使いたい場合はflotr2という感じでしょうか。もっともグラフ・チャートを作成するJavaScriptライブラリはこの他にもたくさんありますから、機会があったら他のライブラリも使ってみたいと思います。

パズドラ練習アプリ

特徴

ノーマルモードで練習
操作時間を気にせずじっくりドロップの動きを確認できます。
なにがなんでもコンボをしなければいけないときに
Edit画面でパズドラの盤面と同じドロップ配置を作成し練習できます。

このアプリはコンボ吸収をする敵がでてきたときや4つ消し3コンボがしたい場合など、コンボを確実に決めなければいけないときに役立ちます。

想定している手順

  1. コンボをしなければいけないときがやってくる
  2. パソコンを立ち上げる
  3. パズドラ練習アプリのページをひらく
  4. Edit画面へ移動し、スマホを見ながらドロップを配置する(手動)
  5. Play画面に戻り、パズルと再配置を繰り返しながらルートを見つける(自力)
  6. 再生やパズルを繰り返し、見つけたルートをがんばって覚える(根性)
  7. パズドラに戻りチャレンジ

手間隙かかりますが、その分の見返りは期待できると思います。ただし練習し過ぎたせいで緊張したり途中で忘れて固まってしまうことも考えられます。もし途中でわからなくなったら無理に思い出そうとせず無心でパズルをした方がいいと思います(体験談)。

コンボの判定について

最初に思いついた方法は画像処理で使われる4連結ラベリングです。判定対象のドロップの色を白、それ以外の色を黒とした2値画像を作成し、ラベリング処理後、特徴量からコンボとみなすかどうかを判定する方法です。この方法で評価してみようかなと思ったのですが、肝心のラベリング処理と特徴量からのコンボ判定処理のコーディングがたいへんそうなことと、これら一連の処理をドロップの色の数だけループするのは処理速度的にどうかという疑問が浮かび止めました。
結局コーディングのしやすさ優先で処理単位ごとにモジュール化していったところ以下のようになりました。

  1. 水平方向に走査し横コンボを検出、上段との結合チェック
  2. 垂直方向に走査し縦コンボを検出、左段との結合チェック
  3. 横コンボと縦コンボを結合

おそらくもっといい方法があるはずです。例えば一回の走査で縦と横について処理を行ったり画像処理的なアプローチをしたりドロップの色ごとにテーブルを持ったりコンボの可能性のある部分(新しいドロップがセットされる周辺)だけ調べるなど。また記述についても、ループの数を減らすほうがいいのかループ内の判定文を減らすほうがいいのか、値を関数の引数で渡すのか関数内でget関数を使うべきかなど悩みどころはたくさんあります。とはいえ時間がかかりますしとりあえず問題なく動いているようなのでいったん終わりにして、機会があれば再考しようかなと思っています。またラベリングや特徴量抽出を行うライブラリを見つけたら使ってみたいです。

懸案事項

  1. パズドラでコンボ成立ドロップが消える順番が分からなかったのでとりあえずコンボを検出した順番にしました。
  2. スマホの場合ドロップが動かないことがありました。jQuery UIのdraggable機能を使っているのですが、start()メソッド後に頻繁に呼ばれるはずのdrag()メソッドが呼ばれない感じがします。PC上ではうまくいっています。またリロードすると大丈夫そうなので、ページの初回アクセスに起因するものと考えています。touch-punch.min.jsも関係あるのかもしれませんが謎です。

パズドラ スタミナ管理ツール

特徴

スタミナのたまり具合が一目瞭然
スタミナ50きざみで時間がわかります

パズドラの現在の仕様では、スタミナは3分間で1回復します。パズドラした後ってよく「3分で1だから1時間で20、5時間で100だから …」と計算しませんか?私はなぜか覚えられなくて毎回「3分で1だから」から始まります。
このツールは現在のスタミナを初期値として入力しグラフ作成ボタンを押すと、スタミナ回復の推移をグラフ化して表示します。いったんグラフを作成するといちいちパズドラにログインしなくてもスタミナを確認できます。
やってることは単にスタミナMAX値の到達時間を計算して直線を引いているだけです。データ点はちょっと工夫してスタミナ50きざみにしてみました。スタミナのカウントはパズドラと異なり時分に同期させました。タイマー10msでセンスしていますがDOMアクセスを時分単位に減らすためです。そのためパズドラのスタミナ回復時間の「あとxx:xx」の表示とぴったり合わせてグラフを作成したとしても誤差が生じることになります。誤差は計算上スタミナ1相当(±3分以内)のため実用上問題ないと考えています。

まとめ

どちらもHTML/JavaScriptで作っているのでそのままさくっとAndroidアプリにすることができるのですが止めました。さすがに数年遅いかなと。今だと7x6盤面とかコンボ加算スキルなどもでてきましたし。
そもそもAndroid上で使うためにはEdit画面でのドロップ配置の仕組み(スクショを撮ってドロップの色抽出から自動配置とか、パズドラの上に透過レイヤを載せて色を複写するとか?)を作らないといけなさそうでハードル高過ぎです。
今後は便利な機能やおもしろそうなアイデアが浮かんだらこっそり追加でもしようかなと思っています。

タイピングの練習ができるサイト e-typing

タイピングの練習ができるサイト e-typing をご紹介します。とはいっても、けっこう有名なサイトみたいでwikiにも載っていますし公式サイトでも会員登録数が100万人を超えたとか100人に一人がe-typingを使った経験がある!?などと書かれています。
私がこのサイトを知ったきっかけが何だったのか思い出せないのですが、知ることができてよかったと思っています。この記事も誰かが e-typing を知るきっかけになればと思います。

公式サイト

インターネットでタイピング練習 イータイピング

e-typingのおもなコンテンツ

  • 腕試しレベルチェック
  • 今日の指トレ
  • 今月のタイピング
  • 練習メニュー
  • タイピングバラエティ

これらのコンテンツについて個人的な感想を書いてみます。あくまで個人的なことですのであしからず。
e-typingのメインコンテンツとなるのが腕試しレベルチェックだと思います。ランキング形式になっていて、いつでもどこでも何度でもチャレンジできます。このランキング要素がe-typingの目玉の一つだと思います。順位が上がると楽しいですからね。また、ランキングの上位陣のスコアを見ると驚きます。順位が2桁台だときっとランキングを見るのが楽しいだろうなと思います。私はだいたい3桁台後半なので想像しかできませんが。
今日の指トレは続けていた時期もあったのですが、今はやらなくなってしまいました。反射神経はよくなりそうですがなんかあまり楽しめないなと。
今月のタイピングもランキング形式になっていて、こちらは長文を打つことができます。これけっこう楽しいです。途中で間違えるとどこから打ちなおせばいいのか分からなくなることがありローマ字で書かれた文章から探すことになるのがたいへんですが。ようは間違えなければいいのですがこれがなかなか。
個人的にお気に入りなのが練習メニュー応用練習のなかの短文練習15文字長文練習です。長文練習今月のタイピングとほぼ同じですが、ランキングがないのであせったりすることもなくミス0を目指しつつお題の童話や名作を読みながら打つことができます。一定のリズムでタイピングを続けているとなんか落ち着いてくるんですよね。

ちなみに腕試しレベルチェックの結果は以下のように表示されます。スコアは正確さを重要視したタイピングの指標(詳細は謎)、WPM(words per minute)は一分あたりの入力文字数ということです。

蛇足になりますがこの記録は今の私のほぼ限界です。このときランキング3桁台後半でした。

メリット

タイピングの練習をすることで得られるメリットを考えてみました。

  • タイピングが速くなる(タイプミスが減る)
  • ストレス解消
  • 手を使うことで脳が刺激される(かもしれない)
  • 爪が伸びたのが分かる

まとめ

過去メールを調べてみたところ私は今年の8月26日にe-typingに登録しました。これまで毎日こつこつ練習してきたわけではなく、練習しても効果が見えなくて飽きたり、しばらく放置していたこともあります。でも最近復活しました。速度ではなくミス0を目指すようにしたら楽しくなったのです。速度と違いミスの数を目標にすると達成感を毎日得ることができます。これってけっこう大きなポイントだと思っています。また、練習の効果を示せるようになったらブログで紹介したいと思います(はたしてその日は来るのだろうか?つづく)。

JavaScriptのapply()とcall()

いつも忘れるので具体的な使い方を残しておこうと思います。自分のためのメモで目新しいことは何もありません。記事の最後にapply()とcall()の引数の型がどっちが配列でどっちが可変長引数リストか忘れない覚え方を載せました。そもそも間違えないとツッコまれそうですが、もし私と同様のお悩みをお持ちの方がいらっしゃいましたら、ご一読いただけたらと思います。

参考サイト

MDN(Function.prototype.apply)
MDN(Function.prototype.call)

apply(), call()とは

JavaScriptの関数はオブジェクトであり、すべての関数がプロパティとメソッドを持っています。このデフォルトで実装されているメソッドのなかにapply()とcall()があります。

JavaScriptの関数を実行すると、呼び出し元から引数とともにthis(コンテクスト、またはコンテキスト)が暗黙的に必ず渡されます。apply()とcall()はこのthisを自由に設定できるメソッドです。

構文

fun.apply(this, array);
引数:コンテクストと配列1個
fun.call(this, arg1, arg2, arg3, …);
引数:コンテクストと可変長の引数

使い方

最大値/最小値を取得する

var array = [0, 6, 12, -1, 3];

// 自力で検出する場合
var max = min = array[0];
for (var i=1; i<array.length; i++) {
  if (max < array[i]) max = array[i];
  if (min > array[i]) min = array[i];
}
console.log(min, max);	// -1 12

// Mathメソッドを使う
// 比較対象の個数が定数の場合はそのまま使える
// でも10個とか100個とか書きたくない
// ちなみに第一引数は使用されないのでnullでも問題なし
Math.min(Math, [0], [1], [2], [3], [4]);
Math.max(Math, [0], [1], [2], [3], [4]);
console.log(min, max);	// -1 12

// Mathメソッドのapply()を使う
// 配列を渡すことができる
var min = Math.min.apply(Math, array);
var max = Math.max.apply(Math, array);
console.log(min, max);	// -1 12

配列のようなオブジェクトに配列メソッドを使う

配列のようなオブジェクトは本物の配列ではないため、直接Arrayクラスのメソッドを使うことはできません。Arrayクラスのメソッドを使うには、Array.prototypeの配列メソッドからapply()またはcall()を呼び出し、第一引数のコンテクストに配列のようなオブジェクトを指定します。

配列のようなオブジェクト

argumentsオブジェクト
関数の引数
getElementsByClassName(“クラス名”)
指定したクラス名を持つ要素
getElementsByName(“name属性”)
指定したname属性を持つ要素
getElementsByTagName(“タグ名”)
指定したタグ名を持つ要素
querySelectorAll(“セレクタ”)
指定したセレクタにマッチする要素

よく使う配列メソッド

slice
配列の部分取り出し(元の配列を変更しない)
forEach/map
配列の各要素に対して関数を実行
// ex. 配列のようなオブジェクトを配列に変換
// 配列のメソッドが使えるようになる
var args = Array.prototype.slice.call(arguments);
var args = [].slice.call(arguments);	// 上記と同じ式

// ex. 指定したクラスを持つすべての要素のテキストを書き換える
// 上記の変換を使って配列のメソッドforEach()を呼び出す
var elems = document.getElementsByClassName("counter");
var array = Array.prototype.slice.call(elems);
array.forEach(function(elem) {
  elem.textContent = "0";
});

// これをcall()メソッドを使って書き直すと以下のようになる
var elems = document.getElementsByClassName("counter");
Array.prototype.forEach.call(elems, function (elem) {
  elem.textContent = "0";
});

// ex. セレクタで指定されたすべての要素のクラスを書き換える
// querySelectorAll()は便利
var elems = document.querySelectorAll(".signal");
Array.prototype.forEach.call(elems, function(elem) {
  elem.classList.remove("red");
  elem.classList.add("blue");
});

// ex. セレクタで指定されたすべての要素のサイズを配列にして出力する
// map()の場合もforEach()と同じように使える
var elems = document.querySelectorAll(".signal");
var size = Array.prototype.map.call(elems, function(elem) {
  return {w: elem.offsetWidth, h: elem.offsetHeight};
});

// ex. 可変長の引数を使用する関数を呼び出す
function sum() {
  for (var i=0, n=0; i<arguments.length; i++) {
    n += arguments[i];
  }
  return n;
}
var answer = sum(2,4,6,8,10,12,14);
var array = [2,4,6,8,10,12,14];		// 配列で扱いたい
var answer = sum.apply(this, array);	// そんなときはapply

apply()とcall()どっちを使う?

引数の型の違いがあるだけでどっちも同じように使えます。どっちを使ったらいいか迷ったら、コードがきれいに見えるほうを採用すればいいと思います。

apply()とcall()の引数の型がどっちが配列でどっちが可変長引数リストか忘れない覚え方

どっちがどっちか覚えられず悩んでいたときがありました。読み方、連想、語呂合わせ… いろいろ試しましたが効果がなく、毎回ググるしかないのかとあきらめかけていました。そもそも関数名が(apply: 適用する)、(call: 呼ぶ)とか、引数の型にぜんぜん関係ないではありませんか。単純にcallbyAry()やcallbyArg()みたいにしてくれていれば… そんなしょうもないことを考えていたある日のこと、突然天啓を授かりました。
その内容は以下の図式になります。

apply >>> arrly >>> array === 配列

これを見たらもう忘れないと思います。
以上です。