最近雀魂玩的很多,于是决定自己写一个立直麻将的程序,进行机器学习生成ai。
立直麻将的规则太繁琐,我先实现了简单麻将的功能,包括:
1.建立牌海,实现随机洗牌
2.生成四位玩家,分发初始手牌
3.实现按序抓牌、打牌
4.实现胡牌检测,包括自摸和点炮
5.编写简单的切牌算法,为手中每张牌加权,每次切除最不需要的牌
其中1~4已经较完善,5还只是最无脑的算法,按牌型加权。
并且还不能吃碰杠。
后面可能会做一下图形化界面、人机交互。重头还是切牌算法,看能不能让深度学习一下。
2022/7/27更新
贴一下程序结果
发牌:
模切:
对局结果:自摸
对局结果:点炮
对局结果:荒牌流局
还不能读牌河、考虑番数等等,后面会做。
下面是代码
#include#include #include #include //设置全局变量——玩家手牌数组 static int player1[15]; static int player2[15]; static int player3[15]; static int player4[15]; static int base[136] = { 11,12, 13, 14, 15, 16, 17, 18, 19, 11,12, 13, 14, 15, 16, 17, 18, 19, 11,12, 13, 14, 15, 16, 17, 18, 19, 11,12, 13, 14, 15, 16, 17, 18, 19, 31,32, 33, 34, 35, 36, 37, 38, 39, 31,32, 33, 34, 35, 36, 37, 38, 39, 31,32, 33, 34, 35, 36, 37, 38, 39, 31,32, 33, 34, 35, 36, 37, 38, 39, 51,52, 53, 54, 55, 56, 57, 58, 59, 51,52, 53, 54, 55, 56, 57, 58, 59, 51,52, 53, 54, 55, 56, 57, 58, 59, 51,52, 53, 54, 55, 56, 57, 58, 59, 71,72, 73, 74, 75, 76, 77, 71,72, 73, 74, 75, 76, 77, 71,72, 73, 74, 75, 76, 77, 71,72, 73, 74, 75, 76, 77 }; void MakeRand(int base[], int count) { int i; srand((unsigned int)time(NULL)); for( i = 0; i < count-1 ; i++) { int num = i + rand()%(count -1-i); int temp = base[i]; base[i] = base[num]; base[num] = temp; } //return base[146]; } void decode(int num) { int typeword = (num-num%10)/10; if(typeword == 1) {printf(" %d", num%10); printf("萬 ") ;} else if(typeword == 3) {printf(" %d", num%10); printf("饼 ") ;} else if(typeword == 5) {printf(" %d", num%10); printf("索 ") ; } else switch(num%10) { case 1:printf(" 東 ");break; case 2:printf(" 南 ");break; case 3:printf(" 西 ");break; case 4:printf(" 北 ");break; case 5:printf(" 白 ");break; case 6:printf(" 發 ");break; case 7:printf(" 中 ");break; } } void AotoCollation(int nums[],int count) { int i, j, temp, isSorted; for(i=0; i nums[j+1]) { temp = nums[j]; nums[j] = nums[j+1]; nums[j+1] = temp; isSorted = 0; } } if(isSorted) break; } } void getcard(int hand[14], int playernum, int nowget ) { int k; hand[13]=nowget; printf("nn手牌 for Player%d: 摸到↓n",playernum); int i; for ( i = 0; i < 14; i++) decode(hand[i]); if(playernum==1) { for(k=0;k<14;k++){player1[k]=hand[k];} } if(playernum==2) { for(k=0;k<14;k++){player2[k]=hand[k];} } if(playernum==3) { for(k=0;k<14;k++){player3[k]=hand[k];} } if(playernum==4) { for(k=0;k<14;k++){player4[k]=hand[k];} } } int putcard(int hand[],int playernum, int putnum) { int k; int temp = 0; temp = hand[putnum-1]; hand[putnum-1] = 99; printf(" 打出--->"); decode(temp); AotoCollation(hand, 14); if(playernum==1) { for(k=0;k<13;k++){player1[k]=hand[k];} } if(playernum==2) { for(k=0;k<13;k++){player2[k]=hand[k];} } if(playernum==3) { for(k=0;k<13;k++){player3[k]=hand[k];} } if(playernum==4) { for(k=0;k<13;k++){player4[k]=hand[k];} } return temp; } int hupai(int hand[15]) { AotoCollation(hand,14); int temphand[15]; int temphandnew[15]; int i,j,m,n=0,x,y; int temp = 0, addup = 0 ; int count1 = 0, count2 = 0, rest = 12; int grouphead; for(i=0;i<13;i++) { temp = hand[i]; for(j=i+1;j0) { grouphead = temphand[m]; count2=0; if(temphand[m+1]==grouphead)//刻子 { count2++; if(temphand[m+2]==grouphead) { count2++; if(count2==2) { rest=rest-3; temphand[m]=0; temphand[m+1]=0; temphand[m+2]=0; continue; } } } count2=0; for(x=m+1;x<15;x++) { if(m-(m%10)/10==7)continue; if(temphand[x]==grouphead+1)//顺子 { count2++; for(y=x+1;y<15;y++) { if(temphand[y]==grouphead+2) { count2++; if(count2==2) { rest=rest-3; temphand[m]=0; temphand[x]=0; temphand[y]=0; } } } } } } } //printf("%d",rest); if(rest==0) { //printf("n荣胡!!!"); return 1; } } } } //printf("nNot ting..."); return 0; } int value(int inthand[]) { //判断14张手牌每张牌价值,并按价值排序 //价值取决于形成雀头或面子的难易度 int i,j,m,n,x,y; int hand[20]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; int hand2[20]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};//便于顺子判断 int value2[15]={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14}; for(i=0;i<14;i++) { hand[i]=inthand[i]; hand2[i]=inthand[i]; } int value[20]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; int now; //基本价值 for(i=0;i<14;i++) { j=i; if(hand[j]==11||hand[j]==19||hand[j]==31||hand[j]==39||hand[j]==51||hand[j]==59) {value[j]=value[j]+5;} if(hand[j]==12||hand[j]==18||hand[j]==32||hand[j]==38||hand[j]==52||hand[j]==58) {value[j]=value[j]+10;} if(hand[j]==13||hand[j]==17||hand[j]==33||hand[j]==37||hand[j]==53||hand[j]==57) {value[j]=value[j]+20;} if(hand[j]==14||hand[j]==15||hand[j]==16||hand[j]==34||hand[j]==35||hand[j]==36||hand[j]==54||hand[j]==55||hand[j]==56) {value[j]=value[j]+30;} if(hand[j]==71||hand[j]==72||hand[j]==73||hand[j]==74) {value[j]=value[j]+0;} if(hand[j]==75||hand[j]==76||hand[j]==77) {value[j]=value[j]+5;} } //对子 for(x=0;x<7;x++) { for(i=0;i<13;i++) { if(hand2[i]==hand2[i+1] && hand2[i+1]!=hand2[i+2] && hand2[i]!=hand2[i-1] && (hand2[i]==hand2[i+2]-1 && hand[i]==hand2[i+3]-2)!=1//11 11 12 13 && (hand2[i]==hand2[i-1]+1 && hand[i]==hand2[i-2]+2)!=1)//11 12 13 13 { if(hand[i]==hand[i+1] && hand[i+2]==hand[i+3] && hand[i+4]==hand[i+5])//一杯口 { value[i]=value[i]+80; value[i+1]=value[i+1]+80; value[i+2]=value[i+2]+80; value[i+3]=value[i+3]+80; value[i+4]=value[i+4]+80; value[i+5]=value[i+5]+80; for(j=0;j<8-i;j++) //去掉一杯口 { hand2[j+i]=hand2[j+i+6]; value2[j+i]=value2[j+i+6]; } } if(hand2[i]==71,72,73,74,75,76,77) { value[value2[i]]=value[value2[i]]+35; value[value2[i+1]]=value[value2[i+1]]+35; }//白 白 else { value[value2[i]]=value[value2[i]]+30; value[value2[i+1]]=value[value2[i+1]]+30; } if(hand2[i]==hand2[i-1]+1 && hand2[i+1]==hand2[i+2]-1) //11 12 12 13 去掉一个 12 { for(j=1;j<14-i;j++) { hand2[j+i]=hand2[j+i+1]; value2[j+i]=value2[j+i+1]; } } else for(j=0;j<14-i;j++) //去掉孤立的对子 { hand2[j+i]=hand2[j+i+2]; value2[j+i]=value2[j+i+2]; } } } } //刻子11 11 11, 杠暂定无价值 for(x=0;x<3;x++) { for(i=0;i<12;i++) { if(hand2[i-1]!=hand2[i] && hand2[i]==hand2[i+1] && hand2[i+1]==hand2[i+2] && hand2[i]!=0) { value[value2[i]]=value[value2[i]]+60; value[value2[i+1]]=value[value2[i+1]]+60; value[value2[i+2]]=value[value2[i+2]]+60; if(hand2[i]==hand2[i-1]+1 && hand2[i+2]==hand2[i+3]-1)//11 12 12 12 13 给12 12对子的价值然后去掉12 12 { value[value2[i]]=value[value2[i]]-60+30; value[value2[i+1]]=value[value2[i+1]]-60+30; value[value2[i+2]]=value[value2[i+2]]-60; for(j=1;j<12-i;j++) { hand2[j+i]=hand2[j+i+2]; value2[j+i]=value2[j+i+2]; } } else for(j=0;j<14-i;j++) { hand2[j+i]=hand2[j+i+3]; value2[j+i]=value2[j+i+3]; } } } } for(i=0;i<14;i++)//字牌的顺子不算顺子 { if(hand2[i]-(hand2[i]%10)==70) { hand2[i]=0; } } //顺子诸多长度 //顺子在理牌后容易被分割,对子刻子部分已经去掉形如“11 12 12 12 13”结构中的多余对子 for(i=0;i<12;i++) { if(hand2[i]+1==hand2[i+1] && hand2[i+1]+1==hand2[i+2] && hand2[i]!=hand2[i-1]+1)//确保hand[i]是顺子的头部 { value[value2[i]] = value[value2[i]]+45; value[value2[i+1]] = value[value2[i+1]]+45; value[value2[i+2]] = value[value2[i+2]]+45; for(j=0;j<14-i;j++) { hand2[j+i]=hand2[j+i+3]; value2[j+i]=value2[j+i+3]; } } } //14 15 for(i=0;i<12;i++) { if(hand2[i]==hand2[i+1]-1 && hand2[i]!=0) { value[value2[i]]=value[value2[i]]+30; value[value2[i+1]]=value[value2[i+1]]+30; } } //14 16 for(i=0;i<11;i++) { if(hand2[i]==hand2[i+1]-2 && hand2[i+1]!=0) { value[value2[i]]=value[value2[i]]+20; value[value2[i+1]]=value[value2[i+1]]+20; } } printf("n"); for(n=0;n<14;n++) { if(value[n]<10) { printf(" %d ",value[n]); } else if(value[n]>99) { printf(" %d ",value[n]); } else printf(" %d ",value[n]); } printf("<---Value"); int cardnum[14]={0,1,2,3,4,5,6,7,8,9,10,11,12,13}; for(x=0;x<13;x++) { if(value[x] ",playernum); if(win1==1) { printf("Player1!!n胡牌牌型为:"); for ( m = 0; m < 13; m++) { decode(player1[m]); } printf("+"); } if(win2==1) { printf("Player2!!n胡牌牌型为:"); for ( m = 0; m < 13; m++) { decode(player2[m]); } printf("+"); } if(win3==1) { printf("Player3!!n胡牌牌型为:"); for ( m = 0; m < 13; m++) { decode(player3[m]); } printf("+"); } if(win4==1) { printf("Player4!!n胡牌牌型为:"); for ( m = 0; m < 13; m++) { decode(player4[m]); } printf("+"); } decode(dianpaopai); return 1; } else return 0; } 主函数部分 int main() { int i=0; int ii=0; srand((unsigned)time(NULL)); //int player1[14], player2[14], player3[14], player4[14]; MakeRand (base,136); for (i = 0; i<13;i++) { player1[i] = base[ii]; ii++; } for (i = 0; i<13;i++) { player2[i] = base[ii]; ii++; } for (i = 0; i<13;i++) { player3[i] = base[ii]; ii++; } for (i = 0; i<13;i++) { player4[i] = base[ii]; ii++; } AotoCollation (player1,13); AotoCollation (player2,13); AotoCollation (player3,13); AotoCollation (player4,13); printf("手牌 for Player1:n"); for (i = 0; i < 13; i++) decode(player1[i]); printf("nn"); printf("手牌 for Player2:n"); for ( i = 0; i < 13; i++) decode(player2[i]); printf("nn"); printf("手牌 for Player3:n"); for ( i = 0; i < 13; i++) decode(player3[i]); printf("nn"); printf("手牌 for Player4:n"); for ( i = 0; i < 13; i++) decode(player4[i]); int dora1 = base[126]; printf("nnDORA1指示牌 :"); decode(dora1); int gameresult; for(i=0;i<30;i++) { gameresult=drive(i); if(gameresult==2){printf("n荒牌流局!"); return 0;} if(gameresult==1){return 0;} } }



