配牌を取った時のシャンテン数(通常手のみ)の割合をシミュレートします。いままで作ったプログラムを使って結果がどんな感じになるかを見てみましょう。
プログラムの解説と実行
それでは実行してみましょう。プログラムの手順は次のフローチャートを参考にしてください。親がサイコロを振って配牌を取り出すイメージです。13牌で配牌を取る作業は終了です。最後のチョンチョンのチョンの部分は省きますのであしからず。なお、牌山シャッフルの乱数処理は「Mersenne Twister in JavaScript」を使用しています。
Mersenne Twister in JavaScriptと牌山を生成する処理は牌山を生成するを参考にしてください。
実行方法と試行回数に要する時間
[開始]ボタンで作業をスタートします。試行回数は1000回です。[中断]ボタンで作業を途中で終わらせることができます。試行回数はプログラム中のグローバル変数の初期値を書きかえれば変更できます。
var numTrials = 1000;//試行回数:この値を変えることで試行回数を調整できます
私のPC環境だと作業が終わるまで約2分かかりました(下囲みを参考)。
動作チェックをしたPC環境
- OS
- Windows7Home Premium Service Pack 1
- CPU
- Inel Core i5 CPU 750 2.67Ghz 2.67Ghz
- 実装メモリ
- 6.00GB
- システムの種類
- 64ビットオペレーティングシステム
- ブラウザ
- Google Chrome 64ビット版
作業が終わったら[結果を出力]ボタンで集計結果を確認できます。
JavaScriptソースコード
本記事で紹介したサンプルプログラムをダウンロードできます。
ダウンロードをする前にお読みください
- サイトで紹介している記事の内容や公開しているプログラムの動作は100%保障するものではありません。
- 当プログラム使用による如何なる不具合やトラブル、損害の責任も負いかねます。
- 当プログラムは断り無く内容が変わることがあります。
- 当プログラムを別サイトで配布することは禁止します。
- サポートはいたしません。
- 自己責任にてご利用くださいませ。
以上をご確認の上、プログラムのダウンロードをお願いいたします。
- 本プログラムはjQueryを組み込んだ状態じゃないと動作しません。ご注意ください。
- 乱数処理は「Mersenne Twister in JavaScript」を使用しています。
- 牌山をシャッフルする処理は「麻雀C言語プログラム集」の牌山を参考にしています。
- シャンテン数算出プログラムは、通常手のアガリとシャンテン数を算出する~再帰呼び出し版のプログラムを利用します。
サンプルプログラムのソースコード
ソースコードは折りたたんであります。[+]を押すと、折りたたまれたソースコードが開きます。[-]を押すと、コードは折りたたまれます。
+ program_015.jsを開く
//グローバル変数============================================================== var stopFlg=0;//繰り返し処理に割り込んで中断させるためのフラグ var haipaiSyanten = [0,0,0,0,0,0,0,0,0];//シャンテン数を格納する配列 var numTrials = 1000;//試行回数:この値を変えることで試行回数を調整できます var count = 1;//試行回数をカウント //======================================================================================= //サイコロの目を出す関数 //spotsmin以上spotsmax以下の乱数が生成される。【(最大値 - 最小値 + 1) + 最小値】 function makeSpotsDice(){ var spotsmax = 6;//最大値 var spotsmin = 1;//最小値 var spotsdice = Math.random()*(spotsmax - spotsmin + 1) + spotsmin;// spotsdice = Math.floor(spotsdice); //少数以下を丸める return spotsdice; } //============================================================================== $("#startBtn").click(function() { var syanten_suu=0;//シャンテン数 var dice = 0;//サイコロの目 //初期化 //count = 1;//試行回数カウント count = 0;//試行回数カウント stopFlg = 0;//中断フラグの初期化 haipaiSyanten = [0,0,0,0,0,0,0,0,0]; //要素のキャッシュ var cachepaiTehai = $("#paiTehai"); var cacheSyantenCount = $("#SyantenCount"); var cacheSyantenCheck = $("#SyantenCheck"); //一定時間ごとに処理を繰り返させる処理 var timer = setInterval(function(){ //手牌の初期化 tehai = [0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0]; makePaiYama();//牌山を生成する関数を呼び出す shufflePaiYama();//牌山をシャッフルする関数を呼び出す dice = makeSpotsDice() + makeSpotsDice();//サイコロを振る count++; //サイコロの目に合わせて取り出した牌を表示する (function (){ var yamaNo; var paiga=""; cachepaiTehai.empty(); //配牌を牌山の1~3ブロックまでを取り出す処理 for(var i=0;i<3;i++){ for(var j=0;j<4;j++){ yamaNo = dice*2 + j + 16*i;//親が取り出す牌の番地 tehai[yama[yamaNo]]++;//牌番号に対応した番地に1を加算する paiga = "<span class=\"" + paiType[yama[yamaNo]].cssSprite + "\"></span>";//cssスプライトの牌画を配置 cachepaiTehai.append(paiga); } } //13牌目を取り出す処理 yamaNo = dice*2 + 16*3;//親が取り出す13牌目の番地 tehai[yama[yamaNo]]++;//牌番号に対応した番地に1を加算する paiga = "<span class=\"" + paiType[yama[yamaNo]].cssSprite + "\"></span>";//cssスプライトの牌画を配置 cachepaiTehai.append(paiga); })(); checkReddora();//赤ドラの有無をチェックする関数を呼び出す moveReddora();//赤ドラを配列内で移動させる preTempTehai = $.extend(true, [], tehai);//tehai配列のバックアップを取る syanten_suu = syantenCheck();//通常手のシャンテン数を調べる関数を呼び出す haipaiSyanten[syanten_suu]++;//シャンテン数に対応した番地に1を加算する //試行回数を表示させる cacheSyantenCount.empty().append(count); //シャンテン数を表示させる cacheSyantenCheck.empty().append("シャンテン数 = " + syanten_suu); //繰り返し処理を終了させる処理 //if(count++ == (numTrials - 1)||stopFlg==1){ if(count == numTrials||stopFlg==1){ clearInterval(timer); } }, 100);//0.1秒毎に処理を実行する }); //============================================================================== //中断ボタンの処理 $("#stopBtn").click(function() { stopFlg = 1;//停止のフラグを立てる }); //======================================================================================= //シャンテン数の合計を出力する処理 $("#outputSyantenBtn").click(function() { //要素のキャッシュ var cacheSyantenCheck = $("#SyantenCheck"); //各シャンテン数を表示させる //cacheSyantenCheck.empty().append("試行回数:" + (count - 1) + "回<br>"); cacheSyantenCheck.empty().append("試行回数:" + count + "回<br>"); for(var i=0;i<9;i++){ //cacheSyantenCheck.append("シャンテン数 = " + i + " : " + haipaiSyanten[i] + "回:" + persentSyanten(haipaiSyanten[i],count - 1) + "%<br>"); cacheSyantenCheck.append("シャンテン数 = " + i + " : " + haipaiSyanten[i] + "回:" + persentSyanten(haipaiSyanten[i],count) + "%<br>"); } }); //======================================================================================= //集計結果をパーセント表記に変換する関数 function persentSyanten(syanten_kyokusuu,num){ var result; if(syanten_kyokusuu>0){ result = Math.floor((syanten_kyokusuu/num)*10000)/100;//パーセント小数2桁 }else{ result = 0; } return result; }
+ makeyama.jsを開く
//============================================================================ //牌山の配列:JSON形式 //============================================================================ var paiYama = [ {"No":0,"paiName":"一萬","paiNo":1}, {"No":1,"paiName":"一萬","paiNo":1}, {"No":2,"paiName":"一萬","paiNo":1}, {"No":3,"paiName":"一萬","paiNo":1}, {"No":4,"paiName":"二萬","paiNo":2}, {"No":5,"paiName":"二萬","paiNo":2}, {"No":6,"paiName":"二萬","paiNo":2}, {"No":7,"paiName":"二萬","paiNo":2}, {"No":8,"paiName":"三萬","paiNo":3}, {"No":9,"paiName":"三萬","paiNo":3}, {"No":10,"paiName":"三萬","paiNo":3}, {"No":11,"paiName":"三萬","paiNo":3}, {"No":12,"paiName":"四萬","paiNo":4}, {"No":13,"paiName":"四萬","paiNo":4}, {"No":14,"paiName":"四萬","paiNo":4}, {"No":15,"paiName":"四萬","paiNo":4}, {"No":16,"paiName":"赤五萬","paiNo":0}, {"No":17,"paiName":"五萬","paiNo":5}, {"No":18,"paiName":"五萬","paiNo":5}, {"No":19,"paiName":"五萬","paiNo":5}, {"No":20,"paiName":"六萬","paiNo":6}, {"No":21,"paiName":"六萬","paiNo":6}, {"No":22,"paiName":"六萬","paiNo":6}, {"No":23,"paiName":"六萬","paiNo":6}, {"No":24,"paiName":"七萬","paiNo":7}, {"No":25,"paiName":"七萬","paiNo":7}, {"No":26,"paiName":"七萬","paiNo":7}, {"No":27,"paiName":"七萬","paiNo":7}, {"No":28,"paiName":"八萬","paiNo":8}, {"No":29,"paiName":"八萬","paiNo":8}, {"No":30,"paiName":"八萬","paiNo":8}, {"No":31,"paiName":"八萬","paiNo":8}, {"No":32,"paiName":"九萬","paiNo":9}, {"No":33,"paiName":"九萬","paiNo":9}, {"No":34,"paiName":"九萬","paiNo":9}, {"No":35,"paiName":"九萬","paiNo":9}, {"No":36,"paiName":"一筒","paiNo":11}, {"No":37,"paiName":"一筒","paiNo":11}, {"No":38,"paiName":"一筒","paiNo":11}, {"No":39,"paiName":"一筒","paiNo":11}, {"No":40,"paiName":"二筒","paiNo":12}, {"No":41,"paiName":"二筒","paiNo":12}, {"No":42,"paiName":"二筒","paiNo":12}, {"No":43,"paiName":"二筒","paiNo":12}, {"No":44,"paiName":"三筒","paiNo":13}, {"No":45,"paiName":"三筒","paiNo":13}, {"No":46,"paiName":"三筒","paiNo":13}, {"No":47,"paiName":"三筒","paiNo":13}, {"No":48,"paiName":"四筒","paiNo":14}, {"No":49,"paiName":"四筒","paiNo":14}, {"No":50,"paiName":"四筒","paiNo":14}, {"No":51,"paiName":"四筒","paiNo":14}, {"No":52,"paiName":"赤五筒","paiNo":10}, {"No":53,"paiName":"五筒","paiNo":15}, {"No":54,"paiName":"五筒","paiNo":15}, {"No":55,"paiName":"五筒","paiNo":15}, {"No":56,"paiName":"六筒","paiNo":16}, {"No":57,"paiName":"六筒","paiNo":16}, {"No":58,"paiName":"六筒","paiNo":16}, {"No":59,"paiName":"六筒","paiNo":16}, {"No":60,"paiName":"七筒","paiNo":17}, {"No":61,"paiName":"七筒","paiNo":17}, {"No":62,"paiName":"七筒","paiNo":17}, {"No":63,"paiName":"七筒","paiNo":17}, {"No":64,"paiName":"八筒","paiNo":18}, {"No":65,"paiName":"八筒","paiNo":18}, {"No":66,"paiName":"八筒","paiNo":18}, {"No":67,"paiName":"八筒","paiNo":18}, {"No":68,"paiName":"九筒","paiNo":19}, {"No":69,"paiName":"九筒","paiNo":19}, {"No":70,"paiName":"九筒","paiNo":19}, {"No":71,"paiName":"九筒","paiNo":19}, {"No":72,"paiName":"一索","paiNo":21}, {"No":73,"paiName":"一索","paiNo":21}, {"No":74,"paiName":"一索","paiNo":21}, {"No":75,"paiName":"一索","paiNo":21}, {"No":76,"paiName":"二索","paiNo":22}, {"No":77,"paiName":"二索","paiNo":22}, {"No":78,"paiName":"二索","paiNo":22}, {"No":79,"paiName":"二索","paiNo":22}, {"No":80,"paiName":"三索","paiNo":23}, {"No":81,"paiName":"三索","paiNo":23}, {"No":82,"paiName":"三索","paiNo":23}, {"No":83,"paiName":"三索","paiNo":23}, {"No":84,"paiName":"四索","paiNo":24}, {"No":85,"paiName":"四索","paiNo":24}, {"No":86,"paiName":"四索","paiNo":24}, {"No":87,"paiName":"四索","paiNo":24}, {"No":88,"paiName":"赤五索","paiNo":20}, {"No":89,"paiName":"五索","paiNo":25}, {"No":90,"paiName":"五索","paiNo":25}, {"No":91,"paiName":"五索","paiNo":25}, {"No":92,"paiName":"六索","paiNo":26}, {"No":93,"paiName":"六索","paiNo":26}, {"No":94,"paiName":"六索","paiNo":26}, {"No":95,"paiName":"六索","paiNo":26}, {"No":96,"paiName":"七索","paiNo":27}, {"No":97,"paiName":"七索","paiNo":27}, {"No":98,"paiName":"七索","paiNo":27}, {"No":99,"paiName":"七索","paiNo":27}, {"No":100,"paiName":"八索","paiNo":28}, {"No":101,"paiName":"八索","paiNo":28}, {"No":102,"paiName":"八索","paiNo":28}, {"No":103,"paiName":"八索","paiNo":28}, {"No":104,"paiName":"九索","paiNo":29}, {"No":105,"paiName":"九索","paiNo":29}, {"No":106,"paiName":"九索","paiNo":29}, {"No":107,"paiName":"九索","paiNo":29}, {"No":108,"paiName":"東","paiNo":31}, {"No":109,"paiName":"東","paiNo":31}, {"No":110,"paiName":"東","paiNo":31}, {"No":111,"paiName":"東","paiNo":31}, {"No":112,"paiName":"南","paiNo":32}, {"No":113,"paiName":"南","paiNo":32}, {"No":114,"paiName":"南","paiNo":32}, {"No":115,"paiName":"南","paiNo":32}, {"No":116,"paiName":"西","paiNo":33}, {"No":117,"paiName":"西","paiNo":33}, {"No":118,"paiName":"西","paiNo":33}, {"No":119,"paiName":"西","paiNo":33}, {"No":120,"paiName":"北","paiNo":34}, {"No":121,"paiName":"北","paiNo":34}, {"No":122,"paiName":"北","paiNo":34}, {"No":123,"paiName":"北","paiNo":34}, {"No":124,"paiName":"白","paiNo":35}, {"No":125,"paiName":"白","paiNo":35}, {"No":126,"paiName":"白","paiNo":35}, {"No":127,"paiName":"白","paiNo":35}, {"No":128,"paiName":"發","paiNo":36}, {"No":129,"paiName":"發","paiNo":36}, {"No":130,"paiName":"發","paiNo":36}, {"No":131,"paiName":"發","paiNo":36}, {"No":132,"paiName":"中","paiNo":37}, {"No":133,"paiName":"中","paiNo":37}, {"No":134,"paiName":"中","paiNo":37}, {"No":135,"paiName":"中","paiNo":37} ]; //グローバル変数============================================================== var yama = new Array(135);//牌山の配列:136牌 //============================================================================== //元になる牌山を生成する関数 function makePaiYama(){ var i; for(i=0;i<136;i++){ yama[i] = paiYama[i].paiNo; } } //============================================================================== //牌山をシャッフルする関数【Mersenne Twister in JavaScriptを利用】 function shufflePaiYama(){ var mt = new MersenneTwister();//MersenneTwister オブジェクトの初期化 var i,j,k; for(i=135;i>0;i--){ j = mt.nextInt(0, 135); // 0 以上 135 未満の乱数(整数)を発生させる k = yama[i];//変数kに退避 yama[i] = yama[j];//乱数で発生した番地の牌を代入する yama[j] = k;//変数Kから戻す } } //=======================================================================================
+ program_015.cssを開く
@charset "utf-8"; #paiTehai > span ,#arrayTehai2 > span{ background-color:transparent; background-image:url(../images/pai.png); background-repeat:no-repeat; background-attachment:scroll; display:inline-block; } .man1{background-position:0px 0px;height:47px;width:31px;} .man2{background-position:-31px 0px;height:47px;width:31px;} .man3{background-position:-62px 0px;height:47px;width:31px;} .man4{background-position:-93px 0px;height:47px;width:31px;} .man5{background-position:-124px 0px;height:47px;width:31px;} .man6{background-position:-155px 0px;height:47px;width:31px;} .man7{background-position:-186px 0px;height:47px;width:31px;} .man8{background-position:-217px 0px;height:47px;width:31px;} .man9{background-position:-248px 0px;height:47px;width:31px;} .man0{background-position:-279px 0px;height:47px;width:31px;} .pin1{background-position:0px -47px;height:47px;width:31px;} .pin2{background-position:-31px -47px;height:47px;width:31px;} .pin3{background-position:-62px -47px;height:47px;width:31px;} .pin4{background-position:-93px -47px;height:47px;width:31px;} .pin5{background-position:-124px -47px;height:47px;width:31px;} .pin6{background-position:-155px -47px;height:47px;width:31px;} .pin7{background-position:-186px -47px;height:47px;width:31px;} .pin8{background-position:-217px -47px;height:47px;width:31px;} .pin9{background-position:-248px -47px;height:47px;width:31px;} .pin0{background-position:-279px -47px;height:47px;width:31px;} .sou1{background-position:0px -94px;height:47px;width:31px;} .sou2{background-position:-31px -94px;height:47px;width:31px;} .sou3{background-position:-62px -94px;height:47px;width:31px;} .sou4{background-position:-93px -94px;height:47px;width:31px;} .sou5{background-position:-124px -94px;height:47px;width:31px;} .sou6{background-position:-155px -94px;height:47px;width:31px;} .sou7{background-position:-186px -94px;height:47px;width:31px;} .sou8{background-position:-217px -94px;height:47px;width:31px;} .sou9{background-position:-248px -94px;height:47px;width:31px;} .sou0{background-position:-279px -94px;height:47px;width:31px;} .ji1{background-position:0px -141px;height:47px;width:31px;} .ji2{background-position:-31px -141px;height:47px;width:31px;} .ji3{background-position:-62px -141px;height:47px;width:31px;} .ji4{background-position:-93px -141px;height:47px;width:31px;} .ji5{background-position:-124px -141px;height:47px;width:31px;} .ji6{background-position:-155px -141px;height:47px;width:31px;} .ji7{background-position:-186px -141px;height:47px;width:31px;} .ji0{background-position:-217px -141px;height:47px;width:31px;}
おすすめレンタルサーバー
エックスサーバー|高速・高機能レンタルサーバー
「オールSSDの快適ハイスペック環境」「国内管理、大容量バックボーン」「独自SSLが無料」「FastCGIなどの高速化機能」「最新のPHP7を実装」など、高機能・高コストパフォーマンスなレンタルサーバーです。※当サイトも「エックスサーバー」で運用しています。