栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

C语言实现简单的ai麻将对局(较大工程,持续更新ing)

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

C语言实现简单的ai麻将对局(较大工程,持续更新ing)

最近雀魂玩的很多,于是决定自己写一个立直麻将的程序,进行机器学习生成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;}
} 

}


​

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1030736.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号