斗地主算法
2015-07-30 14:28
155 查看
不得不承认,算法搁置了一些时间,代码的风格下降了好多! 贴上一个曹点多多且丑的代码! Orz...
题目要求:
编码:3表示3点 ,4表示4点点 。。。。 10表示10点 11表示J 12表示Q 13表示K 14表示A 15表示2 16表示小王 17表示大王
要求:
1)出牌牌型包括(单子,对子, 三张,三带一,三带二,顺子,连对(3连对,4连对,5连对....),四张炸弹,四带一 ,四带二(四带2个单张,四带2个对子),对王炸弹)
2)初始化1副牌(54张),随机发一手牌(17张)显示出来
3)手动输入一个几张牌。判断输入牌是否是1)中的牌型。 程序根据牌型判断自己的手牌是否可以压该牌,如果可以压,则显示可以压的牌型,并输出,从手牌减去已压的牌。显示剩余的牌
4)循环过程要求3 直到牌出完。
代码:
题目要求:
编码:3表示3点 ,4表示4点点 。。。。 10表示10点 11表示J 12表示Q 13表示K 14表示A 15表示2 16表示小王 17表示大王
要求:
1)出牌牌型包括(单子,对子, 三张,三带一,三带二,顺子,连对(3连对,4连对,5连对....),四张炸弹,四带一 ,四带二(四带2个单张,四带2个对子),对王炸弹)
2)初始化1副牌(54张),随机发一手牌(17张)显示出来
3)手动输入一个几张牌。判断输入牌是否是1)中的牌型。 程序根据牌型判断自己的手牌是否可以压该牌,如果可以压,则显示可以压的牌型,并输出,从手牌减去已压的牌。显示剩余的牌
4)循环过程要求3 直到牌出完。
代码:
#define Gxjun #define LOCAL #define Test #include<stdio.h> #include<string.h> #include<stdlib.h> #include<time.h> #define Arr_Len(arr) sizeof(arr)/sizeof(arr[0]) #define maxn 18 int cod[maxn]={0}; int mycod[maxn]; int chu[maxn]; int rtmp[maxn]={0} ,mtmp[maxn]={0}; int mx , mn ; typedef struct LianD { int en ; //连对结尾的牌号 int du ; //最接近的度数 int cnt ; //连对的个数 int tem ; //临时存储的结尾牌号 //复制值函数 void copfun(struct LianD *Ld){ Ld->cnt=cnt; Ld->du=du; Ld->en=en; Ld->tem=tem; } //初始化 void init(){ en=du=cnt=tem=0; } }; enum AlgTyNn{ ShunZi=1 , LianDui }; int cmp(const void * arg , const void * brg){ int * ar =(int *) arg ; int * br =(int *) brg ; return *ar - *br ; } #ifdef Test void init() { int i , cnt=0 ; #ifdef Test #ifndef LOCAL #define LOCAL #endif // LOCAL #endif // Test #ifdef LOCAL freopen("data.in","r",stdin); #endif // Test memset(mycod , 0 , sizeof(mycod)); mycod[cnt]=17; cod[17]=cod[16]=1; //一对王 for(i=3 ; i<16 ;i++) cod[i]=4; while(++cnt<maxn){ scanf("%d" ,&mycod[cnt]); cod[mycod[cnt]]--; } #ifdef Gxjun fclose(stdin); freopen("CON","r",stdin); #endif // Gxjun qsort(mycod+1 , cnt-1 , sizeof(mycod-1) , cmp); } #endif // Test #ifndef Test void init(){ int i , 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<maxn){ hopg = rand()%maxn ; if( hopg>0&&cod[hopg] > 0 ){ cod[hopg]--; mycod[++cnt]=hopg; } } qsort(mycod+1 , cnt-1 , sizeof(mycod-1) , cmp); } #endif // Test //对方输出 void inputs(){ int cnt=0; memset(chu , 0 , sizeof(chu)); while(1){ scanf("%d",&chu[++cnt]); if(chu[cnt]<0) break; } chu[0]=cnt-1 ; //最开头放置纸牌的数目 } //打印剩余 void output(){ printf(" | 剩牌系: "); //剩余牌系 int cont=0; for(int j=3 ; j<maxn ;j++){ cont+=mtmp[j]; for(int k=0; k<mtmp[j] ; k++){ printf("%d ",j); } } mtmp[0]=cont; printf("\t剩牌数: [ %d ]",mtmp[0]); puts(""); } //计数排序 void connt(int *tmp , const int ss []){ //memset(tmp ,0 ,sizeof(tmp)); tmp[0]=ss[0]; for(int i= 1 ; i<=ss[0] ; i++) tmp[ss[i]]++; //计数排序 } //判断是否有炸弹或者王炸 void ZhaDan(){ for(int i=3 ; i<maxn ;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 ; } //如果是连对处理方案 void AlgLDOrShZi(int var){ int i=mn+1 ,len = mx-mn+1 ,kk=0; struct LianD Ld , Tmpld; Ld.init(); //时间复杂度为0(n^2) for( i = mn+1 ; i<15 ; i++){ Tmpld.init(); Tmpld.tem=i; for(int j=i ; j<i+len ; 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.du) Tmpld.copfun(&Ld); break; } } } if(Ld.cnt == len){ puts("提示:"); for(i=Ld.en; i<Ld.en+len ;i++){ mtmp[i]-=var; kk=0; while(kk++<var) printf("%d " ,i); } output(); }else{ //寻求炸弹或者王炸 ZhaDan(); } } //三带的处理情况 void AlgShanDai(){ int pos=0 , cnt=0 , res=0,fcnt=0; int mcnt=0 , mpos=0 ; //分析牌型 for(int i=mn;i<=mx ;i++){ if(rtmp[i]==3){ pos=i; cnt++; }else if(rtmp[i]>0){ res+=rtmp[i]; //统计剩余牌的数量 fcnt++; } } if((fcnt==cnt&&res%cnt==0)||(fcnt<cnt&&(fcnt*res==cnt||0==res))) ; else{ puts("输出的牌不符合规则!请重新输出:"); return ; } res/=cnt; for(int i=pos-cnt+2 ; i<=pos; i++){ if(rtmp[i]!=3){ puts("输出的牌不符合规则!请重新输出:"); return ; } } //如果为三带情况 即 cnt =1 for(int i=pos-cnt+2 ; i<17 ;i++){ if(mtmp[i]==3){ mpos=i; mcnt++; }else mcnt=0; if(mcnt==cnt) break; } //查询副牌是否能够满足 if(mcnt==cnt){ //说明有解决方案 int stpos = mpos - cnt +1 ; int src[maxn]={0} ,tt=0; bool tag = false; for(int i=3 ; i<17 ;i++){ //满足不再连续范围之内的即可333444不能为3,4 if(i<stpos||i>mpos){ if(mtmp[i]>=res){ for(int kk=0 ; kk<mtmp[i] ;kk+=res){ src[tt++]=i; if(tt==cnt){ tag = true; break; } } } } if(tag) break ; } if(tt==cnt){ //则解决方案为 int mstpos = mpos - cnt +1; for(int i=mstpos ; i<=mpos ; i++){ printf("%d %d %d " ,i,i,i); mtmp[i]-=3; } //打印副牌 for(int i=0; i<tt ;i++){ for(int k=0 ;k<res ;k++){ printf("%d ",src[i]); } mtmp[src[i]]-=res; } output(); //打印剩余牌 } }else{ //查询是否有炸弹 ZhaDan(); } } //四带情况 void AlgSiDai(){ if(chu[0]>4) ZhaDan(); else{ for(int i=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 ; } } //对子的情况 void AlgDuiZi(){ for(int i=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(); } //对于个子的情况 void AlgGreZi(){ for(int i=chu[1]+1 ; i<18 ;i++) { if(mtmp[i]>0&&mtmp[i]<4){ printf("%d \n",i); mtmp[i]-=1; output(); return ; } } ZhaDan(); } //查询对应的方案 //对子 bool IsDuiZi(){ if(chu[0]==2) //则必定是对子 return true; return false ; } //个子 bool IsGreZi(){ if(chu[0]==1) //则必定是对子 return true; return false ; } //判断是否是顺子 bool IsShunZi(){ //顺子的条件 if(chu[0]>4){ if((mx-mn+1==chu[0])&& mx<15) return true ; } return false; } //判断是否是连对 bool IsLianDui(){ if(chu[0]>5&&mx<15){ for(int i=mn; i<=mx ;i++) if(rtmp[i]!=LianDui) return false; return true ; } return false; } //判断是否是三带 bool IsShanDai(){ for(int i=mn; i<=mx ;i++) if(rtmp[i]==3) return true; return false ; } //判断是否是四带或者炸弹 bool IsSiDai(){ for(int i=mn; i<=mx ;i++) if(rtmp[i]==4) return true; return false ; } //统计判断 void AlgMxn(){ //求最大值,最小值 for(int i =3 ; i<= 17 ; i++) if(rtmp[i]>0){ mn = i; break; } for(int i =17 ; i>= 3 ; i--) if(rtmp[i]>0){ mx = i; break; } } void print(){ int i; for(i=1; i<17; i++) printf("%d ", mycod[i]); printf("%d\n", mycod[17]); } //检测出牌方 bool checked(){ for(int i=1 ; i<maxn ;i++){ if(cod[i]<rtmp[i]) return false; } if(IsGreZi() ||IsDuiZi() ||IsShunZi() ||IsSiDai() ||IsShanDai()){ for(int i=1; i<=chu[0] ;i++){ cod[chu[i]]--; } } return true ; //如果为一对王 if(chu[0]==2&&mtmp[16]==1&&mtmp[17]==1) return true; return false; } int main(int argc , 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; }; } return 0; }
![](http://images0.cnblogs.com/blog2015/539316/201507/301430474549944.png)
相关文章推荐
- 网络编程系列之六 pcap库拾遗与结构体
- jQuery的简介及语法
- ArrayAdapter(数组适配器)与SimpleAdapter(简单适配器)
- synchronized关键字使用方法
- LVS+keepalived
- 隐藏导航栏时添加在self.view上的Tableview位置产生20个单位的误差
- XML序列化与反序列化
- XCode 6.4 Alcatraz 安装的插件不可用
- shell中cut用法
- C++ 图片类型(所有类型)最简单的复制黏贴实现
- win10控制面板在哪?win10正式版控制面板更新打开方法
- shell脚本进行数据库操作
- android 多个动画特效一起用
- ACdream 1125 ACfun
- 如何实现android蓝牙开发 自动配对连接,并不弹出提示框
- Mysql之入门命令
- OpenSSL::SSL::SSLError: hostname was not match with the server certificate
- 安全测试 Appscan
- CocoaChina 第四个测试
- 如何确认底部的条件及操作原则