电脑版斗地主怎么样玩的(简单AI之斗地主电脑出牌C语言实现篇,日常装逼日常飞,飞到垃圾堆)
斗地主机器出牌核心代码
更多精彩,关注私信“代码”惊喜
运行展示
更多精彩,关注私信“代码”惊喜
完整代码
#define_CRT_SECURE_NO_WARNINGS
#include
#include
#include
#include
#defineArr_Len(arr)(sizeof(arr)/sizeof(arr[0]))
#definemaxn18
/*
1.出牌方式以-1结束
一对8的出发:88-1
*/
intcod[maxn]={0};
intmycod[maxn];
intchu[maxn];
intrtmp[maxn]={0},mtmp[maxn]={0};
intmx,mn;
structLianD
{
inten;//连对结尾的牌号
intdu;//最接近的度数
intcnt;//连对的个数
inttem;//临时存储的结尾牌号
//复制值函数
voidcopfun(structLianD*Ld){
Ld->cnt=cnt;
Ld->du=du;
Ld->en=en;
Ld->tem=tem;
}
//初始化
voidinit(){
en=du=cnt=tem=0;
}
};
enumAlgTyNn{
ShunZi=1,
LianDui
};
intcmp(constvoid*arg,constvoid*brg){
int*ar=(int*)arg;
int*br=(int*)brg;
return*ar-*br;
}
voidinit(){
inti,hopg,cnt=0;
memset(mycod,0,sizeof(mycod));
mycod[cnt]=17;
for(i=3;i<16; i++)
cod[i]=4;
cod[16]=1;//一对王
cod[17]=1;
srand(time(NULL));
while(cnt hopg=rand()%maxn; if(hopg>0&&cod[hopg]>0){ cod[hopg]--; mycod[++cnt]=hopg; } } qsort(mycod+1,cnt-1,sizeof(mycod-1),cmp); } //对方输出 voidinputs(){ intcnt=0; memset(chu,0,sizeof(chu)); while(1){ scanf("%d",&chu[++cnt]); if(chu[cnt]<0) break; } chu[0]=cnt-1;//最开头放置纸牌的数目 } //打印剩余 voidoutput(){ printf("\n剩牌系:\n"); //剩余牌系 intcont=0; for(intj=3;j cont+=mtmp[j]; for(intk=0;k printf("%d",j); } } mtmp[0]=cont; printf("\t剩牌数:[%d]",mtmp[0]); puts(""); } //计数排序 voidconnt(int*tmp,constintss[]){ //memset(tmp,0,sizeof(tmp)); tmp[0]=ss[0]; for(inti=1;i<= ss[0]; i++) tmp[ss[i]]++;//计数排序 } //判断是否有炸弹或者王炸 voidZhaDan(){ for(inti=3;i if(mtmp[i]==4){ printf("%d%d%d%d",i,i,i,i); mtmp[i]-=4; output(); return; } if(mtmp[16]==1&&mtmp[17]==1){ printf("%d%d",16,17); mtmp[16]=mtmp[17]=0; output(); return; } puts("没有牌能压过!"); return; } //如果是连对处理方案 voidAlgLDOrShZi(intvar){ inti=mn+1,len=mx-mn+1,kk=0; structLianDLd,Tmpld; Ld.init(); //时间复杂度为0(n^2) for(i=mn+1;i<15; i++){ Tmpld.init(); Tmpld.tem=i; for(intj=i;j if(mtmp[j]>=var){ if(mtmp[j]==var){ Tmpld.du++; } Tmpld.cnt++; } else{ Tmpld.init(); Tmpld.tem=j+1; } if(Tmpld.cnt==len){ Tmpld.en=Tmpld.tem; if(Ld.en==0||Ld.du Tmpld.copfun(&Ld); break; } } } if(Ld.cnt==len){ puts("提示:"); for(i=Ld.en;i mtmp[i]-=var; kk=0; while(kk++ printf("%d",i); } output(); } else{ //寻求炸弹或者王炸 ZhaDan(); } } //三带的处理情况 voidAlgShanDai(){ intpos=0,cnt=0,res=0,fcnt=0; intmcnt=0,mpos=0; //分析牌型 for(inti=mn;i<= mx; i++){ if(rtmp[i]==3){ pos=i; cnt++; } elseif(rtmp[i]>0){ res+=rtmp[i];//统计剩余牌的数量 fcnt++; } } if((fcnt==cnt&&res%cnt==0)||(fcnt else{ puts("输出的牌不符合规则!请重新输出:"); return; } res/=cnt; for(inti=pos-cnt+2;i<= pos; i++){ if(rtmp[i]!=3){ puts("输出的牌不符合规则!请重新输出:"); return; } } //如果为三带情况即cnt=1 for(inti=pos-cnt+2;i<17; i++){ if(mtmp[i]==3){ mpos=i; mcnt++; } else mcnt=0; if(mcnt==cnt)break; } //查询副牌是否能够满足 if(mcnt==cnt){ //说明有解决方案 intstpos=mpos-cnt+1; intsrc[maxn]={0},tt=0; booltag=false; for(inti=3;i<17; i++){ //满足不再连续范围之内的即可333444不能为3,4 if(i if(mtmp[i]>=res){ for(intkk=0;kk src[tt++]=i; if(tt==cnt){ tag=true; break; } } } } if(tag)break; } if(tt==cnt){ //则解决方案为 intmstpos=mpos-cnt+1; for(inti=mstpos;i<= mpos; i++){ printf("%d%d%d",i,i,i); mtmp[i]-=3; } //打印副牌 for(inti=0;i for(intk=0;k printf("%d",src[i]); } mtmp[src[i]]-=res; } output();//打印剩余牌 } } else{ //查询是否有炸弹 ZhaDan(); } } //四带情况 voidAlgSiDai(){ if(chu[0]>4)ZhaDan(); else{ for(inti=chu[1]+1;i<15; i++){ if(mtmp[i]==4){ printf("%d%d%d%d",i,i,i,i); mtmp[i]-=4; output(); return; } } if(mtmp[16]==1&&mtmp[17]==1){ printf("%d%d",16,17); mtmp[16]=mtmp[17]=0; output(); return; } puts("没有牌能压过!"); return; } } //对子的情况 voidAlgDuiZi(){ for(inti=chu[1]+1;i<16; i++) { if(mtmp[i]>1&&mtmp[i]<4){ printf("%d%d\n",i,i); mtmp[i]-=2; output(); return; } } ZhaDan(); } //对于个子的情况 voidAlgGreZi(){ for(inti=chu[1]+1;i<18; i++) { if(mtmp[i]>0&&mtmp[i]<4){ printf("%d\n",i); mtmp[i]-=1; output(); return; } } ZhaDan(); } //查询对应的方案 //对子 boolIsDuiZi(){ if(chu[0]==2)//则必定是对子 returntrue; returnfalse; } //个子 boolIsGreZi(){ if(chu[0]==1)//则必定是对子 returntrue; returnfalse; } //判断是否是顺子 boolIsShunZi(){ //顺子的条件 if(chu[0]>4){ if((mx-mn+1==chu[0])&&mx<15) returntrue; } returnfalse; } //判断是否是连对 boolIsLianDui(){ if(chu[0]>5&&mx<15){ for(inti=mn;i<= mx; i++) if(rtmp[i]!=LianDui) returnfalse; returntrue; } returnfalse; } //判断是否是三带 boolIsShanDai(){ for(inti=mn;i<= mx; i++) if(rtmp[i]==3) returntrue; returnfalse; } //判断是否是四带或者炸弹 boolIsSiDai(){ for(inti=mn;i<= mx; i++) if(rtmp[i]==4) returntrue; returnfalse; } //统计判断 voidAlgMxn(){ //求最大值,最小值 for(inti=3;i<= 17; i++) if(rtmp[i]>0){ mn=i; break; } for(inti=17;i>=3;i--) if(rtmp[i]>0){ mx=i; break; } } voidprint(){ inti; for(i=1;i<17; i++) printf("%d",mycod[i]); printf("%d\n",mycod[17]); } //检测出牌方 boolchecked(){ for(inti=1;i if(cod[i] returnfalse; } if(IsGreZi() ||IsDuiZi() ||IsShunZi() ||IsSiDai() ||IsShanDai()){ for(inti=1;i<= chu[0]; i++){ cod[chu[i]]--; } } returntrue; //如果为一对王 if(chu[0]==2&&mtmp[16]==1&&mtmp[17]==1) returntrue; returnfalse; } intmain(intargc,char*argv) { init(); memset(mtmp,0,sizeof(mtmp)); connt(mtmp,mycod); print(); while(true){ printf("请出牌:\n"); while(1){ inputs(); memset(rtmp,0,sizeof(rtmp)); connt(rtmp,chu); AlgMxn(); if(checked())break; else puts("输出的牌不符合规则!请重新输出:"); } //如果满足顺子 if(IsGreZi()) AlgGreZi(); else if(IsDuiZi()) AlgDuiZi(); else if(IsShunZi()) AlgLDOrShZi(ShunZi); else if(IsLianDui()) AlgLDOrShZi(LianDui);//对于连对的情况 else if(IsShanDai()) AlgShanDai(); else if(IsSiDai()) AlgSiDai(); if(mtmp[0]<1){ puts("恭喜你,win!"); break; }; } return0; }