import std.stdio : writef; //標準出力writef()使用
import std.random : uniform; //乱数関数uniform()使用
import std.algorithm : swap; //変数入れ替え swap()使用
import std.string : count; //文字列を検索しヒットした数を返す関数 count使用
static auto g_hainame =["{1}","{2}","{3}","{4}","{5}","{6}","{7}","{8}","{9}", //マンズ
"[1]","[2]","[3]","[4]","[5]","[6]","[7]","[8]","[9]", //ソウズ
"(1)","(2)","(3)","(4)","(5)","(6)","(7)","(8)","(9)", //ピンズ
"[E]","[S]","[W]","[N]","{ }","{*}","{+}"]; //東南西北白発中
int main(){
static auto pattern = ["[1][2][3][1][2][3](4)(5)(6)(7)(8)[N][N]", // シュンツ3面待ち
"{2}{3}{4}[5][5][5](6)(6)[E][E][E]{*}{*}", // シャボ待ち
"[1][1][1][2][3][4][5][6][7][8][9][9][9]", // チュウレンポウトウ
"{1}{2}{3}[5][6][7](2)(2)(2)(3)(4)[N][N]", // 変則3面待ち
"[3][4][5][5][6][7][8][9][9][9][W][W][W]", // メンホン5面待ち
"[2][3][3][3][3][4][5][6][7][7][7][7][8]"]; // メンチン7面待ち
int haipai[34];
int machihai[34];
for(int i=0;i<pattern.length;i++){
mj_ChangeHaiData(haipai,pattern[i]);
mj_PutTemochi(haipai);
mj_IsTempai(haipai,machihai);
writef("\n");
mj_PutTemochi(machihai);
writef("\n");
}
return 0;
}
int mj_IsTempai(int[] in_haipai,int[] out_machihai) {
int ments,janto;
out_machihai[]=0;
for(int i=0;i<34;i++) {
in_haipai[i]++;
janto = mj_CountMents(in_haipai,&ments);
if(janto && ments == 4){
out_machihai[i]++;
}
in_haipai[i]--;
}
return 0;
}
int mj_CountMents(int[] in_haipai,int *out_ments){
int h[34] = in_haipai;
int jantou = 0;
int ments_start_couts = 0;
int ments_start_shunts = 0;
int max_ments = 0;
int big;
h[] = in_haipai;
for(int i=0;i<34;i++) {
if(h[i]>=2){
h[i]-=2;
jantou++;
ments_start_couts = mj_CountMents_couts(h);
ments_start_shunts = mj_CountMents_shunts(h);
// mj_PutHaiName(i);
// writef("%d ",ments_start_couts);
// writef("%d ",ments_start_shunts);
if ( ments_start_couts >= ments_start_shunts ) {
big = ments_start_couts;
} else {
big = ments_start_shunts;
}
if ( big > max_ments ) {
max_ments = big;
}
h[] = in_haipai;
}
}
*out_ments = max_ments;
return jantou;
}
int mj_CountMents_couts(int[] in_haipai) {
auto h = in_haipai;
int ments = 0;
for(int i=0;i<34;i++) {
if(h[i]>=3){
h[i]-=3;
ments++;
ments+=mj_CountMents_shunts(h);
}
}
return ments;
}
int mj_CountMents_shunts(int[] in_haipai) {
auto h = in_haipai;
int ments = 0;
for(int j=0;j<3;j++){
for(int i=0;i<7;i++){
if( h[j*9+i+0]&&
h[j*9+i+1]&&
h[j*9+i+2] ) {
h[j*9+i+0]--;
h[j*9+i+1]--;
h[j*9+i+2]--;
ments++;
ments+=mj_CountMents_couts(h);
i--;
}
}
}
return ments;
}
// 文字列で表示された配牌データを数値データに変換
void mj_ChangeHaiData (int[] haipai,string haistr){
haipai[] = 0;
for(int j=0;j<34;j++){
haipai[j]+=haistr.count(g_hainame[j]);
}
}
// 配牌を全表示
void mj_PutTemochi(int[] haipai){
for(int i=0;i<34;i++) {
for(int j=0;j<haipai[i];j++) {
mj_PutHaiName(i);
}
}
}
// 指定された番号(0~33)の牌を表示する
void mj_PutHaiName(int i){
writef(g_hainame[i]);
}
/*
実行結果
[1][1][2][2][3][3](4)(5)(6)(7)(8)[N][N]
(3)(6)(9)
{2}{3}{4}[5][5][5](6)(6)[E][E][E]{*}{*}
(6){*}
[1][1][1][2][3][4][5][6][7][8][9][9][9]
[1][2][3][4][5][6][7][8][9]
{1}{2}{3}[5][6][7](2)(2)(2)(3)(4)[N][N]
(2)(5)[N]
[3][4][5][5][6][7][8][9][9][9][W][W][W]
[2][4][5][7][8]
[2][3][3][3][3][4][5][6][7][7][7][7][8]
[1][2][4][5][6][8][9]
*/
実行結果の解説
一番上は45678の3面ピアノ待ち
2番目は6と西のシャボ待ち
3番目はチュウレンポウトウ9面待ち
4番目はシャボとシュンツの変則3面待ち
5番目はメンホン5面待ち
6番目はメンチン7面待ち
今回はD言語入門というよりも、もうアルゴリズムの問題です。
C言語で優秀だった、再帰処理はD言語でももちろん使えます。
今回は再帰処理でテンパイ判定してます。
(チートイツとコクシはまだです)
もっといい方法はネット探せばたぶんあるのではないのでしょうか?
この方法ではマシンスペックが低いときついでしょう。
再帰処理ははっきりいって、ムダの多い手抜きプログラムです。
でもコードはすっきりします。
でも再帰処理の概念が難しいのでどうなってんの?
って言う人も多いでしょう。
上のプログラムでは
mj_CountMents_Shunts()と
mj_CountMents_Couts()が
互いに呼び合ってる結構複雑な再帰プログラムです。
どういうことやってるかというと、
まず、雀頭を抜きます。
そして、まずコウツを抜くことから始めて
適当に(適当かよw)
コウツを探索
コウツが見つかったら
シュンツを探索
シュンツが見つかったら
コウツを探索…
????
再帰処理は言葉で説明するのが難しいので
図で説明したほうがはやそうです。
とくに今回は2つの関数で呼び合ってるので良く分からないし、
自分でもこれで、すべてのテンパイに対応できてるかまだ未チェックなので
β版とさせていただきます。
とりあえず、乱数使ってモンテカルロ法でデバッグしますので
少々お待ちください。
どういうことかというと、
適当に配牌しまくって、3時間ぐらいプログラム走らせといて、
ダブルリーチ率が理論値に近くなれば
テンパイプログラムはほぼ成功となるという
ものぐさチェック法ですw
じつはこのモンテカルロ法は
遺伝的アルゴリズムと深い関係もあり
じつは動物の進化もこのように適当に進化したと予想されます。
もともと、生物の進化とは
遺伝子のコピーミス…
長くなるのでやめときます。
それでは失礼しました。
