シミューレーション 小粒プログラミング

#16 第一ツモをツモった時のシャンテン数をシミュレートする

Javascriptで遊ぶ麻雀小粒プログラミング 配牌を取った時のシャンテン数(通常手のみ)の割合をシミュレートします。いままで作ったプログラムを使って結果がどんな感じになるかを見てみましょう。

プログラムの解説と実行

前回のお題の配牌のシャンテン数をシミュレートするに続き、配牌を取ったあとの最初のツモでシャンテン数の割合がどのくらいになるかをシュミレートしてみます。手順は同じです。親がサイコロを振って配牌を取り出すイメージです。13牌で配牌が完了。違いはさらに1牌ツモって手牌が14牌になるだけです。

シャンテン数を算出するフローチャート
▲配牌のシャンテン数を集計する手順

実行方法と試行回数に要する時間

[開始]ボタンで作業をスタートします。試行回数は1000回です。[中断]ボタンで作業を途中で終わらせることができます。試行回数はプログラム中のグローバル変数の初期値を書きかえれば変更できます。

var numTrials = 1000;//試行回数:この値を変えることで試行回数を調整できます

動作チェックをしたPC環境

OS
Windows7Home Premium Service Pack 1
CPU
Inel Core i5 CPU 750 2.67Ghz 2.67Ghz
実装メモリ
6.00GB
システムの種類
64ビットオペレーティングシステム
ブラウザ
Google Chrome 64ビット版

作業が終わったら[結果を出力]ボタンで集計結果を確認できます。

第一ツモをツモったときのシャンテン数をシミューレーションした結果
▲集計結果
シャンテン数の割合を算出した結果は、あくまでシミュレートによるものです。本プログラムで導かれた数値は、実際のリアル麻雀やネット麻雀で一致するとは限りません。参考程度にとどめておいてください。
親の配牌:試行回数 = 0
 
シャンテン数:「0」はテンパイ、「-1」はアガリになります。
 



JavaScriptソースコード

本記事で紹介したサンプルプログラムをダウンロードできます。

ダウンロードをする前にお読みください

  • サイトで紹介している記事の内容や公開しているプログラムの動作は100%保障するものではありません。
  • 当プログラム使用による如何なる不具合やトラブル、損害の責任も負いかねます。
  • 当プログラムは断り無く内容が変わることがあります。
  • 当プログラムを別サイトで配布することは禁止します。
  • サポートはいたしません。
  • 自己責任にてご利用くださいませ。

以上をご確認の上、プログラムのダウンロードをお願いいたします。

サンプルプログラムのソースコード

ソースコードは折りたたんであります。[+]を押すと、折りたたまれたソースコードが開きます。[-]を押すと、コードは折りたたまれます。

+ program_016.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 paiNo13 = dice*2 + 16*3;//親が取り出す13牌目の番地
			var paiNo14 = paiNo13 +4;//親が取り出す14牌目の番地
			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牌目の番地
			yamaNo = paiNo13;//親が取り出す13牌目の番地
			tehai[yama[yamaNo]]++;//牌番号に対応した番地に1を加算する
			paiga = "<span class=\"" + paiType[yama[yamaNo]].cssSprite + "\"></span>";//cssスプライトの牌画を配置
			cachepaiTehai.append(paiga);

			//第一ツモを取り出す処理
			yamaNo = paiNo14;//親が取り出す14牌目の番地
			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]++;//シャンテン数に対応した番地に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 -1) + " : " + 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();//Mersenne­Twister オブジェクトの初期化
	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_016.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を実装」など、高機能・高コストパフォーマンスなレンタルサーバーです。※当サイトも「エックスサーバー」で運用しています。

ウザク式麻雀牌効率学習

麻雀の牌効率を覚えたい初心者向け決定版。読者に大好評の麻雀 定石「何切る」301選麻雀 傑作「何切る」300選の著者が「初心者が何切るを解く前に読んでもらうことで、効率よく学習してもらいたい」という願いを込めた一冊です。

-シミューレーション, 小粒プログラミング
-,