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