1: # include <stdio.h> 2: 3: /* Through, `my' refers to the program, `your' to the player */ 4: 5: # define CTYPE 13 6: # define CTSIZ (CTYPE+1) 7: # define DECK 52 8: # define NOMORE 0 9: # define DOUBTIT (-1); 10: 11: typedef char HAND[CTSIZ]; 12: 13: /* data structures */ 14: 15: short debug; 16: 17: HAND myhand; 18: HAND yourhand; 19: char deck[DECK]; 20: short nextcd; 21: int proflag; 22: 23: /* utility and output programs */ 24: 25: shuffle(){ 26: /* shuffle the deck, and reset nextcd */ 27: /* uses the random number generator `rand' in the C library */ 28: /* assumes that `srand' has already been called */ 29: 30: register i; 31: 32: for( i=0; i<DECK; ++i ) deck[i] = (i%13)+1; /* seed the deck */ 33: 34: for( i=DECK; i>0; --i ){ /* select the next card at random */ 35: deck[i-1] = choose( deck, i ); 36: } 37: 38: nextcd = 0; 39: } 40: 41: choose( a, n ) char a[]; { 42: /* pick and return one at random from the n choices in a */ 43: /* The last one is moved to replace the one chosen */ 44: register j, t; 45: 46: if( n <= 0 ) error( "null choice" ); 47: 48: j = rand() % n; 49: t = a[j]; 50: a[j] = a[n-1]; 51: return(t); 52: } 53: 54: draw() { 55: if( nextcd >= DECK ) return( NOMORE ); 56: return( deck[nextcd++] ); 57: } 58: 59: error( s ) char *s; { 60: fprintf( stderr, "error: " ); 61: fprintf( stderr, s ); 62: exit( 1 ); 63: } 64: 65: empty( h ) HAND h; { 66: register i; 67: 68: for( i=1; i<=CTYPE; ++i ){ 69: if( h[i] != 0 && h[i] != 4 ) return( 0 ); 70: } 71: return( i ); 72: } 73: 74: mark( cd, hand ) HAND hand; { 75: if( cd != NOMORE ){ 76: ++hand[cd]; 77: if( hand[cd] > 4 ){ 78: error( "mark overflow" ); 79: } 80: } 81: return( cd ); 82: } 83: 84: deal( hand, n ) HAND hand; { 85: while( n-- ){ 86: if( mark( hand, draw() ) == NOMORE ) error( "deck exhausted" ); 87: } 88: } 89: 90: char *cname[] { 91: "NOMORE!!!", 92: "A", 93: "2", 94: "3", 95: "4", 96: "5", 97: "6", 98: "7", 99: "8", 100: "9", 101: "10", 102: "J", 103: "Q", 104: "K", 105: }; 106: 107: stats(){ 108: register i, ct, b; 109: 110: if( proflag ) printf( "Pro level\n" ); 111: b = ct = 0; 112: 113: for( i=1; i<=CTYPE; ++i ){ 114: if( myhand[i] == 4 ) ++b; 115: else ct += myhand[i]; 116: } 117: 118: if( b ){ 119: printf( "My books: " ); 120: for( i=1; i<=CTYPE; ++i ){ 121: if( myhand[i] == 4 ) printf( "%s ", cname[i] ); 122: } 123: printf( "\n" ); 124: } 125: 126: printf( "%d cards in my hand, %d in the pool\n", ct, DECK-nextcd ); 127: printf( "You ask me for: " ); 128: } 129: 130: phand( h ) HAND h; { 131: register i, j; 132: 133: j = 0; 134: 135: for( i = 1; i<= CTYPE; ++i ){ 136: if( h[i] == 4 ) { 137: ++j; 138: continue; 139: } 140: if( h[i] ){ 141: register k; 142: k = h[i]; 143: while( k-- ) printf( "%s ", cname[i] ); 144: } 145: } 146: 147: if( j ){ 148: printf( "+ Books of " ); 149: for( i=1; i<=CTYPE; ++i ){ 150: if( h[i] == 4 ) printf( "%s ", cname[i] ); 151: } 152: } 153: 154: printf( "\n" ); 155: } 156: 157: main( argc, argv ) char * argv[]; { 158: /* initialize shuffling, ask for instructions, play game, die */ 159: register c; 160: 161: if( argc > 1 && argv[1][0] == '-' ){ 162: while( argv[1][0] == '-' ) { ++argv[1]; ++debug; } 163: argv++; 164: argc--; 165: } 166: 167: srand( getpid() ); 168: 169: printf( "instructions?\n" ); 170: if( (c=getchar()) != '\n' ){ 171: if( c != 'n' ) instruct(); 172: while( getchar() != '\n' ); 173: } 174: 175: game(); 176: } 177: 178: /* print instructions */ 179: 180: char *inst[] { 181: "`Go Fish' is a childrens' card game.", 182: "The Object is to accumulate `books' of 4 cards", 183: "with the same face value.", 184: "The players alternate turns; each turn begins with one", 185: "player selecting a card from his hand, and asking the", 186: "other player for all cards of that face value.", 187: "If the other player has one or more cards of that face value", 188: "in his hand, he gives them to the first player, and the", 189: "first player makes another request.", 190: "Eventually, the first player asks for a card which", 191: "is not in the second player's hand: he replies `GO FISH!'", 192: "The first player then draws a card from the `pool' of", 193: "undealt cards. If this is the card he had last requested, he", 194: "draws again.", 195: "When a book is made, either through drawing or requesting,", 196: "the cards are laid down and no further action takes", 197: "place with that face value.", 198: "To play the computer, simply make guesses by typing", 199: "a, 2, 3, 4, 5, 6, 7, 8, 9, 10, j, q, or k when asked.", 200: "Hitting return gives you information about the size of", 201: "my hand and the pool, and tells you about my books.", 202: "Saying `p' as a first guess puts you into `pro' level;", 203: "The default is pretty dumb!", 204: "Good Luck!", 205: "", 206: }; 207: 208: instruct(){ 209: register char **cpp; 210: 211: printf( "\n" ); 212: 213: for( cpp = inst; **cpp != '\0'; ++cpp ){ 214: printf( "%s\n", *cpp ); 215: } 216: } 217: 218: game(){ 219: 220: shuffle(); 221: 222: deal( myhand, 7 ); 223: deal( yourhand, 7 ); 224: 225: start( myhand ); 226: 227: for(;;){ 228: 229: register g; 230: 231: 232: /* you make repeated guesses */ 233: 234: for(;;) { 235: printf( "your hand is: " ); 236: phand( yourhand ); 237: printf( "you ask me for: " ); 238: if( !move( yourhand, myhand, g=guess(), 0 ) ) break; 239: printf( "Guess again\n" ); 240: } 241: 242: /* I make repeated guesses */ 243: 244: for(;;) { 245: if( (g=myguess()) != NOMORE ){ 246: printf( "I ask you for: %s\n", cname[g] ); 247: } 248: if( !move( myhand, yourhand, g, 1 ) ) break; 249: printf( "I get another guess\n" ); 250: } 251: } 252: } 253: 254: /* reflect the effect of a move on the hands */ 255: 256: move( hs, ht, g, v ) HAND hs, ht; { 257: /* hand hs has made a guess, g, directed towards ht */ 258: /* v on indicates that the guess was made by the machine */ 259: register d; 260: char *sp, *tp; 261: 262: sp = tp = "I"; 263: if( v ) tp = "You"; 264: else sp = "You"; 265: 266: if( g == NOMORE ){ 267: d = draw(); 268: if( d == NOMORE ) score(); 269: else { 270: 271: printf( "Empty Hand\n" ); 272: if( !v ) printf( "You draw %s\n", cname[d] ); 273: mark( hs, d ); 274: } 275: return( 0 ); 276: } 277: 278: if( !v ) heguessed( g ); 279: 280: if( hs[g] == 0 ){ 281: if( v ) error( "Rotten Guess" ); 282: printf( "You don't have any %s's\n", cname[g] ); 283: return(1); 284: } 285: 286: if( ht[g] ){ /* successful guess */ 287: printf( "%s have %d %s%s\n", tp, ht[g], cname[g], ht[g]>1?"'s":"" ); 288: hs[g] += ht[g]; 289: ht[g] = 0; 290: if( hs[g] == 4 ) madebook(g); 291: return(1); 292: } 293: 294: /* GO FISH! */ 295: 296: printf( "%s say \"GO FISH!\"\n", tp ); 297: 298: newdraw: 299: d = draw(); 300: if( d == NOMORE ) { 301: printf( "No more cards\n" ); 302: return(0); 303: } 304: mark( hs, d ); 305: if( !v ) printf( "You draw %s\n", cname[d] ); 306: if( hs[d] == 4 ) madebook(d); 307: if( d == g ){ 308: printf( "%s drew the guess, so draw again\n", sp ); 309: if( !v ) hedrew( d ); 310: goto newdraw; 311: } 312: return( 0 ); 313: } 314: 315: madebook( x ){ 316: printf( "Made a book of %s's\n", cname[x] ); 317: } 318: 319: score(){ 320: register my, your, i; 321: 322: my = your = 0; 323: 324: printf( "The game is over.\nMy books: " ); 325: 326: for( i=1; i<=CTYPE;++i ){ 327: if( myhand[i] == 4 ){ 328: ++my; 329: printf( "%s ", cname[i] ); 330: } 331: } 332: 333: printf( "\nYour books: " ); 334: 335: for( i=1; i<=CTYPE;++i ){ 336: if( yourhand[i] == 4 ){ 337: ++your; 338: printf( "%s ", cname[i] ); 339: } 340: } 341: 342: printf( "\n\nI have %d, you have %d\n", my, your ); 343: 344: printf( "\n%s win!!!\n", my>your?"I":"You" ); 345: exit(0); 346: } 347: 348: # define G(x) { if(go) goto err; else go = x; } 349: 350: guess(){ 351: /* get the guess from the tty and return it... */ 352: register g, go; 353: 354: go = 0; 355: 356: for(;;) { 357: switch( g = getchar() ){ 358: 359: case 'p': 360: case 'P': 361: ++proflag; 362: continue; 363: 364: case '2': 365: case '3': 366: case '4': 367: case '5': 368: case '6': 369: case '7': 370: case '8': 371: case '9': 372: G(g-'0'); 373: continue; 374: 375: case 'a': 376: case 'A': 377: G(1); 378: continue; 379: 380: case '1': 381: G(10); 382: continue; 383: 384: case '0': 385: if( go != 10 ) goto err; 386: continue; 387: 388: case 'J': 389: case 'j': 390: G(11); 391: continue; 392: 393: case 'Q': 394: case 'q': 395: G(12); 396: continue; 397: 398: case 'K': 399: case 'k': 400: G(13); 401: continue; 402: 403: case '\n': 404: if( empty( yourhand ) ) return( NOMORE ); 405: if( go == 0 ){ 406: stats(); 407: continue; 408: } 409: return( go ); 410: 411: case ' ': 412: case '\t': 413: continue; 414: 415: default: 416: err: 417: while( g != '\n' ) g = getchar(); 418: printf( "what?\n" ); 419: continue; 420: } 421: } 422: } 423: 424: /* the program's strategy appears from here to the end */ 425: 426: char try[100]; 427: char ntry; 428: char haveguessed[CTSIZ]; 429: 430: char hehas[CTSIZ]; 431: 432: start( h ) HAND h; { 433: ; 434: } 435: 436: hedrew( d ){ 437: ++hehas[d]; 438: } 439: 440: heguessed( d ){ 441: ++hehas[d]; 442: } 443: 444: myguess(){ 445: 446: register i, lg, t; 447: 448: if( empty( myhand ) ) return( NOMORE ); 449: 450: /* make a list of those things which i have */ 451: /* leave off any which are books */ 452: /* if something is found that he has, guess it! */ 453: 454: ntry = 0; 455: for( i=1; i<=CTYPE; ++i ){ 456: if( myhand[i] == 0 || myhand[i] == 4 ) continue; 457: try[ntry++] = i; 458: } 459: 460: if( !proflag ) goto random; 461: 462: /* get ones he has, if any */ 463: 464: for( i=0; i<ntry; ++i ){ 465: if( hehas[try[i]] ) { 466: i = try[i]; 467: goto gotguess; 468: } 469: } 470: 471: /* is there one that has never been guessed; if so, guess it */ 472: lg = 101; 473: for( i=0; i<ntry; ++i ){ 474: if( haveguessed[try[i]] < lg ) lg = haveguessed[try[i]]; 475: } 476: /* remove all those not guessed longest ago */ 477: 478: t = 0; 479: for( i=0; i<ntry; ++i ){ 480: if( haveguessed[try[i]] == lg ) try[t++] = try[i]; 481: } 482: ntry = t; 483: if( t <= 0 ) error( "bad guessing loop" ); 484: 485: random: 486: i = choose( try, ntry ); /* make a random choice */ 487: 488: gotguess: /* do bookkeeping */ 489: 490: hehas[i] = 0; /* he won't anymore! */ 491: for( t=1; t<=CTYPE; ++t ){ 492: if( haveguessed[t] ) --haveguessed[t]; 493: } 494: haveguessed[i] = 100; /* will have guessed it */ 495: return(i); 496: 497: }