不得不承认,算法搁置了一些时间,代码的风格下降了好多! 贴上一个曹点多多且丑的代码! 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 直到牌出完。
代码:
1 #define Gxjun 2 #define LOCAL 3 #define Test 4 #include<stdio.h> 5 #include<string.h> 6 #include<stdlib.h> 7 #include<time.h> 8 #define Arr_Len(arr) sizeof(arr)/sizeof(arr[0]) 9 #define maxn 18 10 11 12 int cod[maxn]={0}; 13 int mycod[maxn]; 14 int chu[maxn]; 15 int rtmp[maxn]={0} ,mtmp[maxn]={0}; 16 int mx , mn ; 17 18 typedef struct LianD 19 { 20 int en ; //连对结尾的牌号 21 int du ; //最接近的度数 22 int cnt ; //连对的个数 23 int tem ; //临时存储的结尾牌号 24 //复制值函数 25 void copfun(struct LianD *Ld){ 26 27 Ld->cnt=cnt; 28 Ld->du=du; 29 Ld->en=en; 30 Ld->tem=tem; 31 } 32 //初始化 33 void init(){ 34 en=du=cnt=tem=0; 35 } 36 }; 37 38 enum AlgTyNn{ ShunZi=1 , 39 LianDui 40 }; 41 42 int cmp(const void * arg , const void * brg){ 43 44 int * ar =(int *) arg ; 45 int * br =(int *) brg ; 46 return *ar - *br ; 47 48 } 49 50 #ifdef Test 51 void init() 52 { 53 int i , cnt=0 ; 54 55 56 #ifdef Test 57 #ifndef LOCAL 58 #define LOCAL 59 #endif // LOCAL 60 #endif // Test 61 62 #ifdef LOCAL 63 freopen("data.in","r",stdin); 64 #endif // Test 65 memset(mycod , 0 , sizeof(mycod)); 66 mycod[cnt]=17; 67 cod[17]=cod[16]=1; //一对王 68 for(i=3 ; i<16 ;i++) 69 cod[i]=4; 70 while(++cnt<maxn){ 71 scanf("%d" ,&mycod[cnt]); 72 cod[mycod[cnt]]--; 73 } 74 #ifdef Gxjun 75 fclose(stdin); 76 freopen("CON","r",stdin); 77 #endif // Gxjun 78 qsort(mycod+1 , cnt-1 , sizeof(mycod-1) , cmp); 79 } 80 81 #endif // Test 82 83 #ifndef Test 84 void init(){ 85 86 int i , hopg ,cnt=0 ; 87 memset( mycod , 0 , sizeof(mycod) ) ; 88 mycod[cnt]=17; 89 for(i=3 ; i<16 ;i++) 90 cod[i]=4; 91 cod[16]=1; //一对王 92 cod[17]=1; 93 srand(time(NULL)); 94 95 while(cnt<maxn){ 96 97 hopg = rand()%maxn ; 98 99 if( hopg>0&&cod[hopg] > 0 ){ 100 cod[hopg]--; 101 mycod[++cnt]=hopg; 102 } 103 } 104 qsort(mycod+1 , cnt-1 , sizeof(mycod-1) , cmp); 105 106 } 107 #endif // Test 108 109 //对方输出 110 void inputs(){ 111 112 int cnt=0; 113 memset(chu , 0 , sizeof(chu)); 114 while(1){ 115 scanf("%d",&chu[++cnt]); 116 if(chu[cnt]<0) break; 117 } 118 chu[0]=cnt-1 ; //最开头放置纸牌的数目 119 120 } 121 122 //打印剩余 123 void output(){ 124 125 printf(" | 剩牌系: "); 126 //剩余牌系 127 int cont=0; 128 for(int j=3 ; j<maxn ;j++){ 129 cont+=mtmp[j]; 130 for(int k=0; k<mtmp[j] ; k++){ 131 printf("%d ",j); 132 } 133 } 134 mtmp[0]=cont; 135 printf(" 剩牌数: [ %d ]",mtmp[0]); 136 puts(""); 137 } 138 139 //计数排序 140 void connt(int *tmp , const int ss []){ 141 142 //memset(tmp ,0 ,sizeof(tmp)); 143 tmp[0]=ss[0]; 144 for(int i= 1 ; i<=ss[0] ; i++) 145 tmp[ss[i]]++; //计数排序 146 } 147 148 //判断是否有炸弹或者王炸 149 void ZhaDan(){ 150 151 for(int i=3 ; i<maxn ;i++) 152 if(mtmp[i]==4){ 153 printf("%d %d %d %d ",i,i,i,i); 154 mtmp[i]-=4; 155 output(); 156 return ; 157 } 158 159 if(mtmp[16]==1&&mtmp[17]==1){ 160 printf("%d %d ",16,17); 161 mtmp[16]=mtmp[17]=0; 162 output(); 163 return ; 164 } 165 puts("没有牌能压过!"); 166 return ; 167 } 168 169 170 //如果是连对处理方案 171 void AlgLDOrShZi(int var){ 172 173 int i=mn+1 ,len = mx-mn+1 ,kk=0; 174 struct LianD Ld , Tmpld; 175 176 Ld.init(); 177 //时间复杂度为0(n^2) 178 for( i = mn+1 ; i<15 ; i++){ 179 Tmpld.init(); 180 Tmpld.tem=i; 181 for(int j=i ; j<i+len ; j++){ 182 if(mtmp[j]>=var){ 183 184 if(mtmp[j]==var){ 185 Tmpld.du++; 186 } 187 Tmpld.cnt++; 188 }else{ 189 Tmpld.init(); 190 Tmpld.tem=j+1; 191 } 192 if(Tmpld.cnt==len){ 193 Tmpld.en =Tmpld.tem; 194 if(Ld.en==0||Ld.du<Tmpld.du) 195 Tmpld.copfun(&Ld); 196 break; 197 } 198 } 199 } 200 if(Ld.cnt == len){ 201 puts("提示:"); 202 for(i=Ld.en; i<Ld.en+len ;i++){ 203 mtmp[i]-=var; 204 kk=0; 205 while(kk++<var) 206 printf("%d " ,i); 207 } 208 output(); 209 }else{ 210 //寻求炸弹或者王炸 211 ZhaDan(); 212 } 213 214 } 215 216 //三带的处理情况 217 218 void AlgShanDai(){ 219 220 int pos=0 , cnt=0 , res=0,fcnt=0; 221 int mcnt=0 , mpos=0 ; 222 //分析牌型 223 for(int i=mn;i<=mx ;i++){ 224 if(rtmp[i]==3){ 225 pos=i; 226 cnt++; 227 }else if(rtmp[i]>0){ 228 res+=rtmp[i]; //统计剩余牌的数量 229 fcnt++; 230 } 231 } 232 if((fcnt==cnt&&res%cnt==0)||(fcnt<cnt&&(fcnt*res==cnt||0==res))) ; 233 else{ 234 puts("输出的牌不符合规则!请重新输出:"); 235 return ; 236 } 237 res/=cnt; 238 for(int i=pos-cnt+2 ; i<=pos; i++){ 239 if(rtmp[i]!=3){ 240 puts("输出的牌不符合规则!请重新输出:"); 241 return ; 242 } 243 } 244 245 //如果为三带情况 即 cnt =1 246 for(int i=pos-cnt+2 ; i<17 ;i++){ 247 if(mtmp[i]==3){ 248 mpos=i; 249 mcnt++; 250 }else 251 mcnt=0; 252 if(mcnt==cnt) break; 253 } 254 //查询副牌是否能够满足 255 if(mcnt==cnt){ 256 //说明有解决方案 257 int stpos = mpos - cnt +1 ; 258 int src[maxn]={0} ,tt=0; 259 bool tag = false; 260 for(int i=3 ; i<17 ;i++){ 261 //满足不再连续范围之内的即可333444不能为3,4 262 if(i<stpos||i>mpos){ 263 if(mtmp[i]>=res){ 264 for(int kk=0 ; kk<mtmp[i] ;kk+=res){ 265 src[tt++]=i; 266 if(tt==cnt){ 267 tag = true; 268 break; 269 } 270 } 271 } 272 } 273 if(tag) break ; 274 } 275 if(tt==cnt){ 276 //则解决方案为 277 int mstpos = mpos - cnt +1; 278 for(int i=mstpos ; i<=mpos ; i++){ 279 printf("%d %d %d " ,i,i,i); 280 mtmp[i]-=3; 281 } 282 //打印副牌 283 for(int i=0; i<tt ;i++){ 284 for(int k=0 ;k<res ;k++){ 285 printf("%d ",src[i]); 286 } 287 mtmp[src[i]]-=res; 288 } 289 output(); //打印剩余牌 290 } 291 }else{ 292 293 //查询是否有炸弹 294 ZhaDan(); 295 } 296 } 297 298 //四带情况 299 void AlgSiDai(){ 300 if(chu[0]>4) ZhaDan(); 301 else{ 302 for(int i=chu[1]+1 ; i<15 ; i++){ 303 if(mtmp[i]==4){ 304 printf("%d %d %d %d ",i,i,i,i); 305 mtmp[i]-=4; 306 output(); 307 return ; 308 } 309 } 310 if(mtmp[16]==1&&mtmp[17]==1){ 311 printf("%d %d ",16,17); 312 mtmp[16]=mtmp[17]=0; 313 output(); 314 return ; 315 316 317 318 319 320 } 321 puts("没有牌能压过!"); 322 return ; 323 } 324 } 325 326 327 //对子的情况 328 void AlgDuiZi(){ 329 for(int i=chu[1]+1 ; i<16 ;i++) 330 { 331 if(mtmp[i]>1&&mtmp[i]<4){ 332 printf("%d %d ",i,i); 333 mtmp[i]-=2; 334 output(); 335 return ; 336 } 337 } 338 ZhaDan(); 339 } 340 341 //对于个子的情况 342 void AlgGreZi(){ 343 344 for(int i=chu[1]+1 ; i<18 ;i++) 345 { 346 if(mtmp[i]>0&&mtmp[i]<4){ 347 printf("%d ",i); 348 mtmp[i]-=1; 349 output(); 350 return ; 351 } 352 } 353 ZhaDan(); 354 } 355 356 //查询对应的方案 357 358 //对子 359 360 bool IsDuiZi(){ 361 362 if(chu[0]==2) //则必定是对子 363 return true; 364 return false ; 365 } 366 367 //个子 368 bool IsGreZi(){ 369 370 if(chu[0]==1) //则必定是对子 371 return true; 372 373 return false ; 374 } 375 376 //判断是否是顺子 377 bool IsShunZi(){ 378 379 //顺子的条件 380 if(chu[0]>4){ 381 if((mx-mn+1==chu[0])&& mx<15) 382 return true ; 383 } 384 return false; 385 } 386 387 //判断是否是连对 388 bool IsLianDui(){ 389 if(chu[0]>5&&mx<15){ 390 for(int i=mn; i<=mx ;i++) 391 if(rtmp[i]!=LianDui) 392 return false; 393 return true ; 394 } 395 return false; 396 } 397 398 //判断是否是三带 399 bool IsShanDai(){ 400 401 for(int i=mn; i<=mx ;i++) 402 if(rtmp[i]==3) 403 return true; 404 405 return false ; 406 } 407 408 409 410 //判断是否是四带或者炸弹 411 bool IsSiDai(){ 412 413 for(int i=mn; i<=mx ;i++) 414 if(rtmp[i]==4) 415 return true; 416 417 return false ; 418 } 419 420 421 //统计判断 422 void AlgMxn(){ 423 424 //求最大值,最小值 425 for(int i =3 ; i<= 17 ; i++) 426 if(rtmp[i]>0){ 427 mn = i; 428 break; 429 } 430 for(int i =17 ; i>= 3 ; i--) 431 if(rtmp[i]>0){ 432 mx = i; 433 break; 434 } 435 436 } 437 438 void print(){ 439 440 int i; 441 for(i=1; i<17; i++) 442 printf("%d ", mycod[i]); 443 printf("%d ", mycod[17]); 444 445 } 446 447 //检测出牌方 448 bool checked(){ 449 450 for(int i=1 ; i<maxn ;i++){ 451 if(cod[i]<rtmp[i]) 452 return false; 453 } 454 455 if(IsGreZi() 456 ||IsDuiZi() 457 ||IsShunZi() 458 ||IsSiDai() 459 ||IsShanDai()){ 460 for(int i=1; i<=chu[0] ;i++){ 461 cod[chu[i]]--; 462 } 463 } 464 return true ; 465 //如果为一对王 466 if(chu[0]==2&&mtmp[16]==1&&mtmp[17]==1) 467 return true; 468 return false; 469 } 470 471 int main(int argc , char * argv) 472 { 473 474 init(); 475 476 memset(mtmp , 0 , sizeof(mtmp)); 477 478 connt(mtmp , mycod); 479 print(); 480 481 while(true){ 482 printf("请出牌: "); 483 while(1){ 484 inputs(); 485 memset(rtmp , 0 ,sizeof(rtmp)); 486 connt(rtmp , chu); 487 AlgMxn(); 488 if(checked()) break; 489 else 490 puts("输出的牌不符合规则!请重新输出:"); 491 } 492 //如果满足顺子 493 if(IsGreZi()) 494 AlgGreZi(); 495 else 496 if(IsDuiZi()) 497 AlgDuiZi(); 498 else 499 if(IsShunZi()) 500 AlgLDOrShZi(ShunZi); 501 else 502 if(IsLianDui()) 503 AlgLDOrShZi(LianDui); //对于连对的情况 504 else 505 if(IsShanDai()) 506 AlgShanDai(); 507 else 508 if(IsSiDai()) 509 AlgSiDai(); 510 511 if(mtmp[0]<1){ 512 puts("恭喜你,win!"); 513 break; 514 }; 515 } 516 return 0; 517 518 }