完全情報麻雀は面白いか?

実際に打った人 http://amou0.blog62.fc2.com/blog-entry-56.html
学生に打たせた論文 http://ci.nii.ac.jp/naid/110006407435/
どうやら非常に疲れるらしい。しかし Computer-Aided にして情報を集約するか、プログラムを作って機械同士で対戦させるとかすれば面白いかも。後付けアリにしたらリンシャンを待ち牌にしてカンするとかすれば不確定性が減るかも。

頭の体操

N回ツモ後の13+N枚をソートする。その中から14枚選んであがれるかどうかを判定しあがれる最小のNを見つける。そのために必要なサブルーチン:
入力は 1123334456 とか、ソートしたマンズのみとかソーズのみとかのデータ。ここからコーツとシュンツを最大何個作れるかを、トイツを一個作る場合と作らない場合について計算する。
入力例

  • 1222345
  • 1233345
  • 1112333

とりあえずアガリ判定コード書いたよ。int agari(int *pai) マンズ、ソーズ、ピンズ、字牌の9+9+9+7種類をそれぞれ何枚持ってるか入っている int pai[9+9+9+7] を渡すと14枚選んで上がれれば1を、そうでなければ0を返します。

#include <stdio.h>
#include <stdlib.h>

// get and remove leftmost shuntu if avail
static int getshun1(int pai[9], int imin)
{
    int i;
    for(i=imin;i<=6;i++)
    {
	if (pai[i]!=0 && pai[i+1]!=0 && pai[i+2]!=0)
	{
	    pai[i]--;
	    pai[i+1]--;
	    pai[i+2]--;
	    return i;
	}
    }
    return -1;
}

// get all available shuntu
//  return number of shuntu
static int getshun(int pai[9], int *res)
{
    int tmp[9];
    int i;
    // copy
    for(i=0;i<9;i++) tmp[i]=pai[i];
    int imin=0;

    while(pai[imin]==0 && imin<8)imin++;

    int tot=0;
    while(1)
    {
	int t1= getshun1(tmp, imin);
	if (t1==-1)break;
	res[tot]=t1;
	tot++;
	if (tot==4)break;
	while(pai[imin]==0 && imin<8)imin++;
    }
    return tot;
}

// get max avail number of shuntu + kotu
int getall(int  pai[9])
{
    int tmp[9];
    int shund[10];
    int nkotu=0;
    int i,ii;
    int kidx[3], kflag[3];
    int nmax=0;
    int nk;

    // count kotu
    for(i=0;i<9;i++)
    {
	if (pai[i]>=3)
	{
	    if (nkotu==3) return 4;
	    kidx[nkotu]=i;
	    nkotu++;
	}
    }

    nmax=nkotu;
    int imax = 1<<nkotu;

    // loop over all possible kotu on/off
    for(ii=0;ii<imax;ii++)
    {
	int b;
	nk=0;
	for(i=0;i<9;i++) tmp[i]=pai[i];//copy
	// init flags
	for(b=0;b<nkotu;b++)
	{
	    if ((1<<b)&ii)
	    {
		kflag[b]=1;
		nk++;
		tmp[ kidx[b]]-=3;
	    }
	    else kflag[b]=0;
	}

	int ns= getshun(tmp, shund);
	nk = nk+ns;

	if (nk >= nmax)
	{
	    nmax=nk;
	}
    }
    return nmax;
}

// get max avail number of shuntu + kotu after removing toitu
static int getall_h(int  pai[9])
{
    int res=-1;
    int i;
    for(i=0;i<9;i++)
    {
	if(pai[i]<2)continue;

	// make it toitu
	pai[i] -=2;
	int r2 = getall(pai);
	pai[i] +=2; // restore
	if (r2 > res) res=r2;
    }

    return res;
}

// get number of jihai kotu, with and without toitu
static int getji(int  pai[7], int h)
{
    int res=0;
    int i;
    int head=0;
    for(i=0;i<7;i++)
    {
	if(pai[i]>=3) res++;
	if(pai[i]==2) head=1;
    }
    if(h==0) return res;

    if (head==1) return res;
    else return res-1;
}

// 7 toitu
static int toi7(int  pai[9*3+7])
{
    int res=0;
    int i;
    for(i=0;i<9*3+7;i++) if (pai[i]>=2) res++;
    if (res>=7) return 1;
    return 0;
}

// kokusi
static int kokusi(int  pai[9*3+7])
{
    //191919 jjjj jjj
    int kpai[13]={0, 0+8, 9, 9+8, 18, 18+8, 27, 28, 29, 30,  31, 32, 33};
    int i;
    int res=1;

    for(i=0;i<13;i++)
    {
	int n=pai[kpai[i]];
	if (n==0) res=0;
	else if (n>=2 && res==1) res = 2;
    }
    if (res==2) return 1;
    return 0;
}

int agari(int *pai)
{
    // toi7 first
    if (toi7(pai))return 1;
    if (kokusi(pai))return 1;

    int *manz=pai;
    int *soz=&pai[9];
    int *pinz=&pai[18];
    int *ji=&pai[27];

    int m1 = getall(manz);
    int m2 = getall_h(manz);

    int s1 = getall(soz);
    int s2 = getall_h(soz);

    int p1 = getall(pinz);
    int p2 = getall_h(pinz);

    int ji1 = getji(ji, 0);
    int ji2 = getji(ji, 1);

    if ((m2!=-1 && m2+s1+p1+ji1 >=4) || 
	    (s2!=-1 && m1+s2+p1+ji1>=4) ||
	    (p2!=-1 && m1+s1+p2+ji1 >=4) ||
	    (ji2!=-1 && m1+s1+p1+ji2 >=4))
    {
	return 1;
    }
    return 0;
}