今月、恒例のINASOFT読者アンケート&プレゼント企画を実施しました。
この中で、抽選をどのような方法で行うか、考えました。
過去の抽選では、そのときそのときでマイブームな人………例えば、直近でフォロワーになった人だったり、特別仲のよい友人だったり、サークルのリーダーだったり、家族だったり、会社の先輩だったりしたこともありました。
さて、現在のマイブームは、パソコンからその地位を奪いつつあるiPadなのですが、ぜひともiPadさんに抽選をやってもらいたいと思いました。
しかし、iPadさんに抽選をやってもらうということは、iPadさんで自作プログラムが動かなければなりません。これだけのために、アップルストアに申請を出すのは手間がかかりすぎです。
というわけで、手軽に標準ブラウザSafariで動く、JavaScriptでプログラムを組むことにしました。
さて、アルゴリズムとしては、次の通り。
簡単そうです。
実際、テキトーに作ったら、IEではきちんと動きました。
が、なぜかSafariでは動かず。あれあれ?と思い次。Firefoxでも動かず。
ネットで調べたところ、原因はすぐにわかりました。とりあえず、書いたプログラムを御覧ください。
<html> <head> <title>抽選プログラム</title> <script type="text/javascript"> Array.prototype.shuffle = function() { var i = this.length; while(i){ var j = Math.floor(Math.random()*i); var t = this[--i]; this[i] = this[j]; this[j] = t; } return this; } function c_lot() { total_num = Number(document.getElementById('total').value); tosen_num = Number(document.getElementById('tosen').value); if (total_num <= 0) { alert("全体数には1以上の値を指定してください。"); return; } else if (tosen_num <= 0) { alert("当選数には1以上の値を指定してください。"); return; } else if (total_num < tosen_num) { alert("全体数は当選数以上である必要があります。"); return; } ret = confirm("抽選を行います。よろしいですか?"); if (ret == true){ ary = new Array(total_num); for(i=0 ; i<total_num ; ++i) { ary[i] = i + 1; } ary.shuffle(); result_text = "■当選結果 = "; for(i=0 ; i<tosen_num ; ++i) { if (i > 0) { result_text += ", " } result_text += "No."+ary[i]; } temp = document.getElementById("result"); temp.innerHTML = result_text; } } </script> </head> <body> <h1>抽選プログラム</h1> <form name="chusen"> 全体数:<input type="text" size="10" name="total" id="total" value="10" /> 当選数:<input type="text" size="10" name="tosen" id="tosen" value="6" /> <input type="button" value="抽選" onClick="c_lot();" /> </form> <br><br><br> <b><font color="#ff0000"> <div id="result"> <small>(ここに結果が表示されます)</small> </div> </font></b> </body> </html>
赤で書かれた部分が、原因を修正したところです。
document.getElementByIdは、その名の通り、IDを使ってフォーム要素から値を取り出す動きをするわけですから、該当する<input>にはID属性が指定されていなければなりません。IEではなぜか、name属性さえあれば読めてしまうのですが、それは罠。
また、Number() で囲まないと、フォームから取り出された値は「文字列」と認識されてしまいますから、その後の大小比較のif文の動きがおかしくなります。具体的には、"10" < "6" という事態が起こりえます(文字列は辞書式による大小比較を行う)。
なるほど。そういうわけですね。
しかし、JavaScriptの、動作環境ごとでの動きの違いって、厄介ですね。
とくに、IEの異端っぷりは異様。
その反面、このプログラムはNintendo3DSでもスマートフォンでも、ブラウザ搭載機種ならなんでもどこでも動きます。なんだか、未来を感じさせてくれますね。
よい勉強になりました。
実際のプログラムはこちら↓
(ここに結果が表示されます)
|
※半角数字以外を入れた場合などに対する検定は入れていないので、あまりイジメないでください。
※このスクリプトは alert() や confirm() を使っているため、ダイアログ表示のできない携帯電話では、正常に動作しません。
そういえば、シャッフルを行っている関数 shuffle について、全然解説していなかったですね。
この関数は、余所様のサンプルコードを拝借したモノですが、シンプルによくできています。
この関数は、「配列クラス」にメンバ関数を追加するような感じで実装されています。こうしておくと、このスクリプト内の配列に対し、シャッフル関数を実行できます。「配列クラス」と言ってしまうと軽く語弊があるわけですが、ここでの理解はその程度で。
では、関数の中の解説を。
random(n) は、0以上n未満の数を、ランダムに返す関数です。基本的には小数で返ります。
random(100)なら0以上100未満の数がランダムで返ります。
floor(n) は、与えられた数を超えない最大の整数を返す関数です。
floor(1.1)なら1を返すし、floor(0.5)なら0を返すし、floor(-1.2)なら-2が返ります。
これを使って、0以上指定数未満の整数をランダムに得ることができます。
ここまでが、ループ内1行目にやっていること。
ループ内2行目からループ内4行目は、変数値のスワップ(入れ替え)をやっています。tはテンポラリ(一時的な)変数と言うことでしょう。
配列の末尾と、上のランダムで決められた数(ただし、その末尾よりも左側にあるもの)を交換します。そして、配列の末尾の位置を1つずつずらしながら、それより左側の要素とランダムに交換します。末尾の位置が0に到達したらおしまい。
これで、配列内の要素のシャッフルが完成です。
サイコロで1〜6の目を出すスクリプトを作ることになったのでこちらに。
|
スクリプトを観たい方は、このページのHTMLソースを見ていただくということで。