シャンテン数 小粒プログラミング

#19 通常手のアガリとシャンテン数を算出する~再帰呼び出し版

Javascriptで遊ぶ麻雀小粒プログラミング
チートイツと国士無双を除く通常手のアガリ判定とシャンテン数を再帰呼び出しで算出する処理を紹介します。

プログラムの解説と実行

アガリ判定とシャンテン数のチェックをする処理を紹介します。アガリ判定とシャンテン数は手牌(tehai)の中身を調べて行います。国士無双、チートイツ、通常手(4面子+1雀頭)の3つの処理に分けて調査します。

通常手のシャンテン数を求める

麻雀は「4メンツ+1雀頭」を集めるゲームです(通常手の場合)。メンツ(コーツやシュンツ)とメンツ候補になるターツやトイツが増える毎にシャンテン数は減っていきます。シャンテン数を求める式は次のようになります。

通常手のシャンテン数を求める式
シャンテン数 = 8 - メンツ数×2 - ターツ数 - 雀頭

上記の式の場合、テンパイは「0」でアガリは「-1」になります。なお、国士無双とチートイツの扱いは別になり、シャンテン数を求める計算式も異なります。このページでは今回は扱いません。

アガリとシャンテン数を求める手順
(1)雀頭がある場合
  1. 雀頭を抜き出す→シュンツを抜き出す→コーツを抜き出す→ターツを抜き出す
  2. 雀頭を抜き出す→コーツを抜き出す→シュンツを抜き出す→ターツを抜き出す
(2)雀頭が無い場合
  1. コーツを抜き出す→シュンツを抜き出す→ターツを抜き出す
  2. シュンツを抜き出す→コーツを抜き出す→ターツを抜き出す

各手順で算出されたシャンテン数を比較して最小のシャンテン数を結果として採用します。プログラムでは手牌の元となるtehai配列から完全に独立したコーツとシュンツを前もって抜いてからクローン(tempTehai配列)を生成し、再帰呼び出しでシャンテン数を計算していきます。

大まかな手順はこんな感じです。コードには手を入れないといけませんが、参考になると幸いです。

リンク牌理/牌効率学習ツール




シャンテン数を求めてみよう

手牌を作ってプログラムの動作を確認してみましょう。操作は簡単です。牌をクリックすると下のパネル内に牌が追加されていくます。[シャンテン数を調べる]ボタンを押すとシャンテン数を調査する手順が表示されます。




手牌:0牌(最大入力数は14牌) ※任意の牌をクリックして消すことができます。
シャンテン数:テンパイは「0」、アガリは「-1」になります。

面子多々(めんつたーた)の場合の処理

ターツの抜き出しとカウントを途中で中断して処理を抜けています。したがって算出したターツ数が実際のターツ数と異ります。

たとえば、下の手牌は「2メンツ+3ターツ+1雀頭」ですが、プログラム内部ではメンツとターツの合計が4つになった時点で処理を抜けて「ターツ数 = 2」を返すようにしています。

mentsu_suu=kanzen_koutsu_suu+koutsu_suu+kanzen_shuntsu_suu+shuntsu_suu;
if(mentsu_suu+taatsu_suu<4){//メンツとターツの合計は4まで

現状での不具合と解決策(解決済2015/11/15)

カンツが混じっている場合シャンテン数が正確に算出されない不具合が見つかっています(2015年3月時点)。下の手牌のシャンテン数は1にならないといけないのですが、結果はテンパイになってしまいます。

これは「東がコーツ、残り1枚の東の単騎待ち」に解釈されるためです。いずれ解決しないといけませんが、今回はとりあえずここまでにしておきます。



JavaScriptソースコード

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

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

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

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

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

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

+ program_019.jsを開く

//============================================================================
//牌の配列:JSON形式
//============================================================================
var paiType = [
	{"No":0,"paiName":"赤五萬","cssSprite":"man0","paigaNo":4},
	{"No":1,"paiName":"一萬","cssSprite":"man1","paigaNo":0},
	{"No":2,"paiName":"二萬","cssSprite":"man2","paigaNo":1},
	{"No":3,"paiName":"三萬","cssSprite":"man3","paigaNo":2},
	{"No":4,"paiName":"四萬","cssSprite":"man4","paigaNo":3},
	{"No":5,"paiName":"五萬","cssSprite":"man5","paigaNo":5},
	{"No":6,"paiName":"六萬","cssSprite":"man6","paigaNo":6},
	{"No":7,"paiName":"七萬","cssSprite":"man7","paigaNo":7},
	{"No":8,"paiName":"八萬","cssSprite":"man8","paigaNo":8},
	{"No":9,"paiName":"九萬","cssSprite":"man9","paigaNo":9},

	{"No":10,"paiName":"赤五筒","cssSprite":"pin0","paigaNo":14},
	{"No":11,"paiName":"一筒","cssSprite":"pin1","paigaNo":10},
	{"No":12,"paiName":"二筒","cssSprite":"pin2","paigaNo":11},
	{"No":13,"paiName":"三筒","cssSprite":"pin3","paigaNo":12},
	{"No":14,"paiName":"四筒","cssSprite":"pin4","paigaNo":13},
	{"No":15,"paiName":"五筒","cssSprite":"pin5","paigaNo":15},
	{"No":16,"paiName":"六筒","cssSprite":"pin6","paigaNo":16},
	{"No":17,"paiName":"七筒","cssSprite":"pin7","paigaNo":17},
	{"No":18,"paiName":"八筒","cssSprite":"pin8","paigaNo":18},
	{"No":19,"paiName":"九筒","cssSprite":"pin9","paigaNo":19},

	{"No":20,"paiName":"赤五索","cssSprite":"sou0","paigaNo":24},
	{"No":21,"paiName":"一索","cssSprite":"sou1","paigaNo":20},
	{"No":22,"paiName":"二索","cssSprite":"sou2","paigaNo":21},
	{"No":23,"paiName":"三索","cssSprite":"sou3","paigaNo":22},
	{"No":24,"paiName":"四索","cssSprite":"sou4","paigaNo":23},
	{"No":25,"paiName":"五索","cssSprite":"sou5","paigaNo":25},
	{"No":26,"paiName":"六索","cssSprite":"sou6","paigaNo":26},
	{"No":27,"paiName":"七索","cssSprite":"sou7","paigaNo":27},
	{"No":28,"paiName":"八索","cssSprite":"sou8","paigaNo":28},
	{"No":29,"paiName":"九索","cssSprite":"sou9","paigaNo":29},

	{"No":30,"paiName":"裏","cssSprite":"ji0","paigaNo":30},
	{"No":31,"paiName":"東","cssSprite":"ji1","paigaNo":31},
	{"No":32,"paiName":"南","cssSprite":"ji2","paigaNo":32},
	{"No":33,"paiName":"西","cssSprite":"ji3","paigaNo":33},
	{"No":34,"paiName":"北","cssSprite":"ji4","paigaNo":34},
	{"No":35,"paiName":"白","cssSprite":"ji5","paigaNo":35},
	{"No":36,"paiName":"發","cssSprite":"ji6","paigaNo":36},
	{"No":37,"paiName":"中","cssSprite":"ji7","paigaNo":37}
];
//============================================================================
//グローバル変数
//============================================================================
var tehai = new Array(37);//手牌の配列:37種
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];
var tempTehai = new Array(37);//preTempTehai配列のクローン

var red5manCount;//赤5マンの数
var red5pinCount;//赤5ピンの数
var red5souCount;//赤5ソウの数

var toitsu_suu;//トイツ数
var koutsu_suu;//コーツ数
var shuntsu_suu;//シュンツ数
var taatsu_suu;//ターツ数
var mentsu_suu;//メンツ数
var syanten_temp;//シャンテン数(作業用用)
var syanten_normal;//シャンテン数(結果用)

var kanzen_koutsu_suu;//完全コーツ数
var kanzen_shuntsu_suu;//完全シュンツ数
var kanzen_Koritsu_suu;//完全孤立牌数
//============================================================================
//赤ドラの有無をチェックしてカウントする処理【赤ドラのカウントを事前にしなかった場合に使う】
//各赤ドラはtehai配列の0,10,20番地にあるものとする
//============================================================================
function checkReddora(){
    //グローバル変数の初期化
    red5manCount=0;//赤5マンの数
    red5pinCount=0;//赤5ピンの数
    red5souCount=0;//赤5ソウの数

    //赤五萬の有無をチェックしてカウントする
    if(tehai[0]){
        red5manCount+=tehai[0];//赤五萬の牌数を追加
    }
    //赤五筒の有無をチェックしてカウントする
    if(tehai[10]){
        red5pinCount+=tehai[10];//赤五筒の牌数を追加
    }
    //赤五索の有無をチェックしてカウントする
    if(tehai[20]){
        red5souCount+=tehai[20];//赤五索の牌数を追加
    }
}
//============================================================================
//赤ドラの有無をチェックして配列操作する処理【シャンテン数やテンパイチェックを実行する前に使う】
//tehai配列内を0→5、10→15、20→25
//============================================================================
function moveReddora(){
    //赤五萬の有無をチェックして番地を移動させる処理
    if(tehai[0]&&red5manCount){
        tehai[5]+=tehai[0];//赤五萬の牌数を五萬の番地5に追加
        tehai[0]=0;//番地0を初期化
    }
    //赤五筒の有無をチェックして番地を移動させる処理
    if(tehai[10]&&red5pinCount){
        tehai[15]+=tehai[10];//赤五筒の牌数を五筒の番地15に追加
        tehai[10]=0;//番地10を初期化
    }
    //赤五索の有無をチェックして番地を移動させる処理
    if(tehai[20]&&red5souCount){
        tehai[25]+=tehai[20];//赤五索の牌数を五索の番地25に追加
        tehai[20]= 0;//番地20を初期化
    }
}
//============================================================================
//赤ドラの有無をチェックして配列内の元の番地に戻す処理
//tehai配列内を5→0、15→10、25→20
//============================================================================
function removeReddora(){
    //赤五萬の有無をチェックして番地を移動:5→0
    if(!tehai[0]&&tehai[5]&&red5manCount){
        tehai[5]--;
        tehai[0]++;
    }
    //赤五筒の有無をチェックして番地を移動:15→10
    if(!tehai[10]&&tehai[15]&&red5pinCount){
        tehai[15]--;
        tehai[10]++;
    }
    //赤五索の有無をチェックして番地を移動:25→20
    if(!tehai[20]&&tehai[25]&&red5souCount){
        tehai[25]--;
        tehai[20]++;
    }
}
//============================================================================
//アガリ判定とシャンテン数を返す関数
//============================================================================
function syantenCheck(){
	var i;
	//初期化
	toitsu_suu=0;//トイツ数
	koutsu_suu=0;//コーツ数
	shuntsu_suu=0;//シュンツ数
	taatsu_suu=0;//ターツ数
	mentsu_suu=0;//メンツ数
	syanten_temp=0;//シャンテン数(計算用)
	syanten_normal=8;//シャンテン数(結果用)

	kanzen_koutsu_suu=0;//完全コーツ数
	kanzen_shuntsu_suu=0;//完全シュンツ数
	kanzen_Koritsu_suu=0;//完全孤立牌数

	tempTehai = $.extend(true, [], tehai);//tehai配列のバックアップを取る

	//前もって完全なシュンツ・コーツ・孤立牌を抜いておく
	kanzen_koutsu_suu = KanzenKoutsuCheck();//完全に独立したコーツを抜き出して個数を返す関数呼び出し
	kanzen_shuntsu_suu = kanzenShuntsuCheck();//完全に独立したシュンツを抜き出して個数を返す関数呼び出し
	kanzen_Koritsu_suu=KanzenKoritsuCheck();//完全に独立した孤立牌を抜き出して個数を返す関数の実行

	//雀頭抜き出し→コーツ抜き出し→シュンツ抜き出し→ターツ候補抜き出し
	for(i=1;i<38;i++){
		//頭抜き出し
		if(tempTehai[i]>=2){
			toitsu_suu++;
			tempTehai[i]-=2;
			mentu_cut1(1);
			tempTehai[i]+=2;
			toitsu_suu--;
		}
	}//for


	//【不要っぽい】雀頭抜き出し→シュンツ抜き出し→コーツ抜き出し→ターツ候補抜き出し
	//for(i=1;i<38;i++){
	//	//頭抜き出し
	//	if(tempTehai[i]>=2){
	//		toitsu_suu++;
	//		tempTehai[i]-=2;
	//		mentu_cut2(1);
	//		tempTehai[i]+=2;
	//		toitsu_suu--;
	//	}
	//}//for

	toitsu_suu=0;
	//【雀頭が無い場合の処理】コーツ抜き出し→シュンツ抜き出し→ターツ候補抜き出し	for(var i=1;i<38;i++){
	mentu_cut1(1);

	//【不要っぽい】雀頭抜き出し→シュンツ抜き出し→コーツ抜き出し→ターツ候補抜き出し
	//mentu_cut2(1);
	return syanten_normal;//最終的な結果
}
//============================================================================
//メンツ抜き出し1【→コーツ抜き出し→シュンツ抜き出し】
//============================================================================
function mentu_cut1(i){
	for(var j=i;j<30;j++){//※字牌のコーツは完全コーツ処理で抜いているの数牌だけで良い
		//コーツ抜き出し
			if(tempTehai[j]>=3){
				mentsu_suu++;
				koutsu_suu++;
				tempTehai[j]-=3;
				mentu_cut1(j);
				tempTehai[j]+=3;
				koutsu_suu--;
		}//if
			//シュンツ抜き出し
			if(tempTehai[j]&&tempTehai[j+1]&&tempTehai[j+2]&&j<28){
				shuntsu_suu++;
				tempTehai[j]--;
				tempTehai[j+1]--;
				tempTehai[j+2]--;
				mentu_cut1(j);//自身を呼び出す
				tempTehai[j]++;
				tempTehai[j+1]++;
				tempTehai[j+2]++;
				shuntsu_suu--;
			}//if
	}//for
	taatu_cut(1);//ターツ抜きへ
	return;
}
//============================================================================
//メンツ抜き出し2【シュンツ抜き出し→コーツ抜き出し】
//============================================================================
function mentu_cut2(i){
	for(var j=i;j<30;j++){//※字牌のコーツは完全コーツ処理で抜いているの数牌だけで良い
			//シュンツ抜き出し
			if(tempTehai[j]&&tempTehai[j+1]&&tempTehai[j+2]&&j<28){
				shuntsu_suu++;
				tempTehai[j]--;
				tempTehai[j+1]--;
				tempTehai[j+2]--;
				mentu_cut2(j);//自身を呼び出す
				tempTehai[j]++;
				tempTehai[j+1]++;
				tempTehai[j+2]++;
				shuntsu_suu--;
			}//if

			//コーツ抜き出し
				if(tempTehai[j]>=3){
					mentsu_suu++;
					koutsu_suu++;
					tempTehai[j]-=3;
					mentu_cut2(j);
					tempTehai[j]+=3;
					koutsu_suu--;
			}//if
	}//for
	taatu_cut(1);//ターツ抜きへ
	return;
}
//============================================================================
//ターツ抜き出し
//============================================================================
function taatu_cut(i){
	for(var j=i;j<38;j++){
		mentsu_suu=kanzen_koutsu_suu+koutsu_suu+kanzen_shuntsu_suu+shuntsu_suu;

		if(mentsu_suu+taatsu_suu<4){//メンツとターツの合計は4まで
			//トイツ抜き出し
			if(tempTehai[j]==2){
				taatsu_suu++;
				tempTehai[j]-=2;
				taatu_cut(j);
				tempTehai[j]+=2;
				taatsu_suu--;
			}

			//リャンメン・ペンチャン抜き出し
			if(tempTehai[j]&&tempTehai[j+1]&&j<29&&j%10<9){
				taatsu_suu++;
				tempTehai[j]--;
				tempTehai[j+1]--;
				taatu_cut(j);
				tempTehai[j]++;
				tempTehai[j+1]++;
				taatsu_suu--;
			}

			//カンチャン抜き出し
			if(tempTehai[j]&&!tempTehai[j+1]&&tempTehai[j+2]&&j<28&&j%10<8){
				taatsu_suu++;
				tempTehai[j]--;
				tempTehai[j+2]--;
				taatu_cut(j);
				tempTehai[j]++;
				tempTehai[j+2]++;
				taatsu_suu--;
			}
		}//if
	}//for

	syanten_temp=8-mentsu_suu*2-taatsu_suu-toitsu_suu;
	if(syanten_temp<syanten_normal) {syanten_normal=syanten_temp;}
	return;
}//function_end
//============================================================================
//完全コーツを抜き出して個数を返す関数
//============================================================================
function KanzenKoutsuCheck(){
	var Kanzenkoutsu_suu = 0;
	var i,j;
	//字牌の完全コーツを抜き出す
	for(i=31;i<38;i++){
		if(tempTehai[i]>=3){
			tempTehai[i]-=3;
			Kanzenkoutsu_suu++;
		}
	}//for

	//数牌の完全コーツを抜き出す
	for(i=0;i<30;i+=10){
		if(tempTehai[i+1]>=3&&!tempTehai[i+2]&&!tempTehai[i+3]){
			tempTehai[i+1]-=3;
			Kanzenkoutsu_suu++;
		}
		if(!tempTehai[i+1]&&tempTehai[i+2]>=3&&!tempTehai[i+3]&&!tempTehai[i+4]){
			tempTehai[i+2]-=3;
			Kanzenkoutsu_suu++;
		}

		//3~7の完全コーツを抜く
		for(j=0;j<5;j++){
			if(!tempTehai[i+j+1]&&!tempTehai[i+j+2]&&tempTehai[i+j+3]>=3&&!tempTehai[i+j+4]&&!tempTehai[i+j+5]){
				tempTehai[i+j+3]-=3;
				Kanzenkoutsu_suu++;
			}
		}
		if(!tempTehai[i+6]&&!tempTehai[i+7]&&tempTehai[i+8]>=3&&!tempTehai[i+9]){
			tempTehai[i+8]-=3;
			Kanzenkoutsu_suu++;
		}

		if(!tempTehai[i+7]&&!tempTehai[i+8]&&tempTehai[i+9]>=3){
			tempTehai[i+9]-=3;
			Kanzenkoutsu_suu++;
		}
	}//for

	return Kanzenkoutsu_suu;
}
//============================================================================
//完全シュンツを抜き出して個数を返す関数
//============================================================================
function kanzenShuntsuCheck(){
	var kanzenshuntsu_suu=0;
	var i;
	//123,456のような完全に独立したシュンツを抜き出すための処理
	////【注意】番地0,10,20,30が「0」の必要あり。事前に赤ドラを移動させる処理をしておく。
	for(i=0;i<30;i+=10){//マンズ→ピンズ→ソーズ
		//123▲▲
		if(tempTehai[i+1]==2&&tempTehai[i+2]==2&&tempTehai[i+3]==2&&!tempTehai[i+4]&&!tempTehai[i+5]){
			tempTehai[i+1]-=2;
			tempTehai[i+2]-=2;
			tempTehai[i+3]-=2;
			kanzenshuntsu_suu+=2;
		}

		//▲234▲▲
		if(!tempTehai[i+1]&&tempTehai[i+2]==2&&tempTehai[i+3]==2&&tempTehai[i+4]==2&&!tempTehai[i+5]&&!tempTehai[i+6]){
			tempTehai[i+2]-=2;
			tempTehai[i+3]-=2;
			tempTehai[i+4]-=2;
			kanzenshuntsu_suu+=2;
		}

		//▲▲345▲▲
		if(!tempTehai[i+1]&&!tempTehai[i+2]&&tempTehai[i+3]==2&&tempTehai[i+4]==2&&tempTehai[i+5]==2&&!tempTehai[i+6]&&!tempTehai[i+7]){
			tempTehai[i+3]-=2;
			tempTehai[i+4]-=2;
			tempTehai[i+5]-=2;
			kanzenshuntsu_suu+=2;
		}

		//▲▲456▲▲
		if(!tempTehai[i+2]&&!tempTehai[i+3]&&tempTehai[i+4]==2&&tempTehai[i+5]==2&&tempTehai[i+6]==2&&!tempTehai[i+7]&&!tempTehai[i+8]){
			tempTehai[i+4]-=2;
			tempTehai[i+5]-=2;
			tempTehai[i+6]-=2;
			kanzenshuntsu_suu+=2;
		}

		//▲▲567▲▲
		if(!tempTehai[i+3]&&!tempTehai[i+4]&&tempTehai[i+5]==2&&tempTehai[i+6]==2&&tempTehai[i+7]==2&&!tempTehai[i+8]&&!tempTehai[i+9]){
			tempTehai[i+5]-=2;
			tempTehai[i+6]-=2;
			tempTehai[i+7]-=2;
			kanzenshuntsu_suu+=2;
		}

		//▲▲678▲
		if(!tempTehai[i+4]&&!tempTehai[i+5]&&tempTehai[i+6]==2&&tempTehai[i+7]==2&&tempTehai[i+8]==2&&!tempTehai[i+9]){
			tempTehai[i+6]-=2;
			tempTehai[i+7]-=2;
			tempTehai[i+8]-=2;
			kanzenshuntsu_suu+=2;
		}

		//▲▲789
		if(!tempTehai[i+5]&&!tempTehai[i+6]&&tempTehai[i+7]==2&&tempTehai[i+8]==2&&tempTehai[i+9]==2){
			tempTehai[i+7]-=2;
			tempTehai[i+8]-=2;
			tempTehai[i+9]-=2;
			kanzenshuntsu_suu+=2;
		}
	}

	for(i=0;i<30;i+=10){//マンズ→ピンズ→ソーズ
		//123▲▲
		if(tempTehai[i+1]==1&&tempTehai[i+2]==1&&tempTehai[i+3]==1&&!tempTehai[i+4]&&!tempTehai[i+5]){
			tempTehai[i+1]--;
			tempTehai[i+2]--;
			tempTehai[i+3]--;
			kanzenshuntsu_suu++;
		}

		//▲234▲▲
		if(!tempTehai[i+1]&&tempTehai[i+2]==1&&tempTehai[i+3]==1&&tempTehai[i+4]==1&&!tempTehai[i+5]&&!tempTehai[i+6]){
			tempTehai[i+2]--;
			tempTehai[i+3]--;
			tempTehai[i+4]--;
			kanzenshuntsu_suu++;
		}

		//▲▲345▲▲
		if(!tempTehai[i+1]&&!tempTehai[i+2]&&tempTehai[i+3]==1&&tempTehai[i+4]==1&&tempTehai[i+5]==1&&!tempTehai[i+6]&&!tempTehai[i+7]){
			tempTehai[i+3]--;
			tempTehai[i+4]--;
			tempTehai[i+5]--;
			kanzenshuntsu_suu++;
		}

		//▲▲456▲▲
		if(!tempTehai[i+2]&&!tempTehai[i+3]&&tempTehai[i+4]==1&&tempTehai[i+5]==1&&tempTehai[i+6]==1&&!tempTehai[i+7]&&!tempTehai[i+8]){
			tempTehai[i+4]--;
			tempTehai[i+5]--;
			tempTehai[i+6]--;
			kanzenshuntsu_suu++;
		}

		//▲▲567▲▲
		if(!tempTehai[i+3]&&!tempTehai[i+4]&&tempTehai[i+5]==1&&tempTehai[i+6]==1&&tempTehai[i+7]==1&&!tempTehai[i+8]&&!tempTehai[i+9]){
			tempTehai[i+5]--;
			tempTehai[i+6]--;
			tempTehai[i+7]--;
			kanzenshuntsu_suu++;
		}

		//▲▲678▲
		if(!tempTehai[i+4]&&!tempTehai[i+5]&&tempTehai[i+6]==1&&tempTehai[i+7]==1&&tempTehai[i+8]==1&&!tempTehai[i+9]){
			tempTehai[i+6]--;
			tempTehai[i+7]--;
			tempTehai[i+8]--;
			kanzenshuntsu_suu++;
		}

		//▲▲789
		if(!tempTehai[i+5]&&!tempTehai[i+6]&&tempTehai[i+7]==1&&tempTehai[i+8]==1&&tempTehai[i+9]==1){
			tempTehai[i+7]--;
			tempTehai[i+8]--;
			tempTehai[i+9]--;
			kanzenshuntsu_suu++;
		}
	}
	return kanzenshuntsu_suu;
}
//============================================================================
//完全孤立牌を抜き出して個数を返す関数
//============================================================================
function KanzenKoritsuCheck(){
	var KanzenKoritsu_suu=0;
	var i,j;
	//字牌の完全孤立牌を抜き出す
	for(i=31;i<38;i++){
		if(tempTehai[i]==1){
			tempTehai[i]--;
			KanzenKoritsu_suu++;
		}
	}

	//数牌の完全孤立牌を抜き出す
	for(i=0;i<30;i+=10){//マンズ→ピンズ→ソーズ
		//1の孤立牌を抜く
		if(tempTehai[i+1]==1&&!tempTehai[i+2]&&!tempTehai[i+3]){
			tempTehai[i+1]--;
			KanzenKoritsu_suu++;
		}
		//2の完全孤立牌を抜く
		if(!tempTehai[i+1]&&tempTehai[i+2]==1&&!tempTehai[i+3]&&!tempTehai[i+4]){
			tempTehai[i+2]--;
			KanzenKoritsu_suu++;
		}

		//3~7の完全孤立牌を抜く
		for(j=0;j<5;j++){
			if(!tempTehai[i+j+1]&&!tempTehai[i+j+2]&&tempTehai[i+j+3]==1&&!tempTehai[i+j+4]&&!tempTehai[i+j+5]){
				tempTehai[i+j+3]--;
				KanzenKoritsu_suu++;
			}
		}
		//8の完全孤立牌を抜く
		if(!tempTehai[i+6]&&!tempTehai[i+7]&&tempTehai[i+8]==1&&!tempTehai[i+9]){
			tempTehai[i+8]--;
			KanzenKoritsu_suu++;
		}
		//9の完全孤立牌を抜く
		if(!tempTehai[i+7]&&!tempTehai[i+8]&&tempTehai[i+9]==1){
			tempTehai[i+9]--;
			KanzenKoritsu_suu++;
		}
	}

	return KanzenKoritsu_suu;
}
//============================================================================
//抜き出した牌とシャンテン数を出力させる処理【動作チェック用】
//============================================================================
$("#SyantenCheckBtn").click(function() {
	$("#paiTehaiSyantenCheck").empty();

	moveReddora();//赤ドラを配列内で移動させる
	var syanten_suu = syantenCheck();//syantenCheck()の動作テスト用関数
	$("#paiTehaiSyanten").empty().append("シャンテン数 = " + syanten_suu);
});
//============================================================================

+ paiput2.jsを開く

//============================================================================
//牌画を操作するための配列:JSON形式
//============================================================================
var paigaType = [
	{"No":0,"paiName":"一萬","cssSprite":"man1","paigaNo":1},
	{"No":1,"paiName":"二萬","cssSprite":"man2","paigaNo":2},
	{"No":2,"paiName":"三萬","cssSprite":"man3","paigaNo":3},
	{"No":3,"paiName":"四萬","cssSprite":"man4","paigaNo":4},
	{"No":4,"paiName":"赤五萬","cssSprite":"man0","paigaNo":0},
	{"No":5,"paiName":"五萬","cssSprite":"man5","paigaNo":5},
	{"No":6,"paiName":"六萬","cssSprite":"man6","paigaNo":6},
	{"No":7,"paiName":"七萬","cssSprite":"man7","paigaNo":7},
	{"No":8,"paiName":"八萬","cssSprite":"man8","paigaNo":8},
	{"No":9,"paiName":"九萬","cssSprite":"man9","paigaNo":9},

	{"No":10,"paiName":"一筒","cssSprite":"pin1","paigaNo":11},
	{"No":11,"paiName":"二筒","cssSprite":"pin2","paigaNo":12},
	{"No":12,"paiName":"三筒","cssSprite":"pin3","paigaNo":13},
	{"No":13,"paiName":"四筒","cssSprite":"pin4","paigaNo":14},
	{"No":14,"paiName":"赤五筒","cssSprite":"pin0","paigaNo":10},
	{"No":15,"paiName":"五筒","cssSprite":"pin5","paigaNo":15},
	{"No":16,"paiName":"六筒","cssSprite":"pin6","paigaNo":16},
	{"No":17,"paiName":"七筒","cssSprite":"pin7","paigaNo":17},
	{"No":18,"paiName":"八筒","cssSprite":"pin8","paigaNo":18},
	{"No":19,"paiName":"九筒","cssSprite":"pin9","paigaNo":19},

	{"No":20,"paiName":"一索","cssSprite":"sou1","paigaNo":21},
	{"No":21,"paiName":"二索","cssSprite":"sou2","paigaNo":22},
	{"No":22,"paiName":"三索","cssSprite":"sou3","paigaNo":23},
	{"No":23,"paiName":"四索","cssSprite":"sou4","paigaNo":24},
	{"No":24,"paiName":"赤五索","cssSprite":"sou0","paigaNo":20},
	{"No":25,"paiName":"五索","cssSprite":"sou5","paigaNo":25},
	{"No":26,"paiName":"六索","cssSprite":"sou6","paigaNo":26},
	{"No":27,"paiName":"七索","cssSprite":"sou7","paigaNo":27},
	{"No":28,"paiName":"八索","cssSprite":"sou8","paigaNo":28},
	{"No":29,"paiName":"九索","cssSprite":"sou9","paigaNo":29},

	{"No":30,"paiName":"裏","cssSprite":"ji0","paigaNo":30},
	{"No":31,"paiName":"東","cssSprite":"ji1","paigaNo":31},
	{"No":32,"paiName":"南","cssSprite":"ji2","paigaNo":32},
	{"No":33,"paiName":"西","cssSprite":"ji3","paigaNo":33},
	{"No":34,"paiName":"北","cssSprite":"ji4","paigaNo":34},
	{"No":35,"paiName":"白","cssSprite":"ji5","paigaNo":35},
	{"No":36,"paiName":"發","cssSprite":"ji6","paigaNo":36},
	{"No":37,"paiName":"中","cssSprite":"ji7","paigaNo":37},
];

//============================================================================
//グローバル変数
//============================================================================
var PaiCount = 0;	//入力された牌の枚数
var PaiNo =[];//牌画表示用

//============================================================================
//牌画を挿入する関数
//============================================================================
$("span","#haiga").on('click', function(event){
	var paiCountMax = 14;//手牌最大数
	var paiNo = $(this).attr("name"); //牌の番号を取得
	var paiName = $(this).attr("class"); //CSSスプライト用のクラス名を取得
	if(PaiCount<paiCountMax){
		if(tehai[paiNo]>3){
			alert("5枚以上の同種牌を置くことはできません。");
			return false;
		}else{
			if(paiNo===0&&red5manCount==1||paiNo==10&&red5pinCount==1||paiNo==20&&red5souCount==1){
				alert("赤ドラは各色1枚までです。");
				return false;
			}
			tehai[paiNo] ++;//手牌
			if(paiNo%10===0){checkReddora();}//赤ドラのチェック
			//PaiNo[PaiCount] = paiNo;//表示用手牌
			PaiNo[PaiCount] = paiType[paiNo].paigaNo;//表示用手牌
			paiSet(PaiCount,paiName);//牌画を表示させる関数を呼び出す
			PaiCount ++;
			$("#paikazu").empty().append(PaiCount);
		}
	}else{
		alert("これ以上は牌を置けません。");
		return false;
	}
});
//============================================================================
//牌を配置する関数
//============================================================================
function paiSet(i,paiName) {
	paiga = "<span class=\"" + paiName + "\"></span>";//cssスプライトの牌画を配置
	var putNo = "#pai" + i;
	$(putNo ,"#paisu").append(paiga);
	return;
}
//============================================================================
//任意の牌を1つ消す処理
//============================================================================
$("td","#paisu").click(function() {
var tdNo = $(this).attr("id"); //牌画を配置したセルのIDを取得
	var paikazu = PaiNo.length;
	if(paikazu === 0){
		alert("これ以上牌を消せません");
		return;
	}else{
		tdNo = tdNo.slice(3,5);//削って番号のみにする
		if(PaiNo[tdNo]==4){red5manCount--;}
		if(PaiNo[tdNo]==14){red5pinCount--;}
		if(PaiNo[tdNo]==24){red5souCount--;}
		tehai[paigaType[PaiNo[tdNo]].paigaNo] --;//手牌
		if(tdNo < paikazu){
			$("td","#paisu").empty();
			PaiNo.splice(tdNo,1);
			for(var i=0;i<paikazu -1 ;i++){
				paiSet(i,paigaType[PaiNo[i]].cssSprite);
			}
		}
		PaiCount --;
		$("#paikazu").empty().append(PaiCount);
	}
});
//============================================================================
//手牌を並べ替える処理
//============================================================================
$("#PaiSortBtn").on('click', function(event){
	paiSort();
});
//============================================================================
//牌を並べ替える関数
//============================================================================
function paiSort() {
	//手牌を並び替える
	var paikazu = PaiNo.length;
	PaiNo.sort(function(b,c){
		return b - c;
	});
	$("td","#paisu").empty();
	for (var i = 0;i<paikazu ;i++){
		paiSet(i,paigaType[PaiNo[i]].cssSprite);
	}
	return;
}
//============================================================================
//リセット処理
//============================================================================
$("#PaiClreaBtn").on('click', function(event){
	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];
	PaiNo.length = 0;//牌を格納した配列の要素をすべて削除
	PaiCount = 0;//カウントのリセット
	$("#paikazu").empty().append("0");
	$("td","#paisu").empty();
	$("#paiTehaiUkeire").empty();
	$("#paiTehaiSyanten").empty();
	red5manCount = 0;//赤5マンの数
	red5pinCount = 0;//赤5ピンの数
	red5souCount = 0;//赤5ソウの数
	$("#paiTehaiSyantenCheck").empty();
});
//============================================================================

+ program_019.cssを開く

@charset "utf-8";

#paiTehai > span , #haiga > span, .haiga > span, td > 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;}


#haiga{
  background-color:#173B0B;
  padding:5px 15px 3px 15px;
  margin-bottom:5px;
  color:#fff;
  -moz-user-select: none;
  -webkit-user-select: none;
  -ms-user-select: none;
}


#pai0,#pai1,#pai2,#pai3{width:0;}

table.style{margin-left:10px;}

table.style tr td{background-color:#fff;}

.style > thead > tr > td {
  vertical-align: bottom;
  border-bottom: 5px solid #ddd;
}

おすすめレンタルサーバー

エックスサーバー|高速・高機能レンタルサーバー

オールSSDの快適ハイスペック環境」「国内管理、大容量バックボーン」「独自SSLが無料」「FastCGIなどの高速化機能」「最新のPHP7を実装」など、高機能・高コストパフォーマンスなレンタルサーバーです。※当サイトも「エックスサーバー」で運用しています。

-シャンテン数, 小粒プログラミング
-,

© 2020 無料麻雀ツール&アプリ 点数計算ラボ