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