1 /*- 2 * Copyright (c) 1990, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Muffy Barkocy. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * $FreeBSD: src/games/fish/fish.c,v 1.9 1999/12/10 16:21:50 billf Exp $ 33 * $DragonFly: src/games/fish/fish.c,v 1.4 2005/07/31 20:40:26 swildner Exp $ 34 * 35 * @(#) Copyright (c) 1990, 1993 The Regents of the University of California. All rights reserved. 36 * @(#)fish.c 8.1 (Berkeley) 5/31/93 37 */ 38 39 #include <sys/types.h> 40 #include <errno.h> 41 #include <fcntl.h> 42 #include <stdio.h> 43 #include <stdlib.h> 44 #include <string.h> 45 #include <unistd.h> 46 #include "pathnames.h" 47 48 #define RANKS 13 49 #define HANDSIZE 7 50 #define CARDS 4 51 52 #define USER 1 53 #define COMPUTER 0 54 #define OTHER(a) (1 - (a)) 55 56 const char *cards[] = { 57 "A", "2", "3", "4", "5", "6", "7", 58 "8", "9", "10", "J", "Q", "K", NULL, 59 }; 60 #define PRC(card) printf(" %s", cards[card]) 61 62 int promode; 63 int asked[RANKS], comphand[RANKS], deck[RANKS]; 64 int userasked[RANKS], userhand[RANKS]; 65 66 static void chkwinner(int, int *); 67 static int compmove(void); 68 static int countbooks(int *); 69 static int countcards(int *); 70 static int drawcard(int, int *); 71 static int gofish(int, int, int *); 72 static void goodmove(int, int, int *, int *); 73 static void init(void); 74 static void instructions(void); 75 static int nrandom(int); 76 static void printhand(int *); 77 static void printplayer(int); 78 static int promove(void); 79 static void usage(void); 80 static int usermove(void); 81 82 int 83 main(int argc, char **argv) 84 { 85 int ch, move; 86 87 while ((ch = getopt(argc, argv, "p")) != -1) 88 switch(ch) { 89 case 'p': 90 promode = 1; 91 break; 92 case '?': 93 default: 94 usage(); 95 } 96 97 srandomdev(); 98 instructions(); 99 init(); 100 101 if (nrandom(2) == 1) { 102 printplayer(COMPUTER); 103 printf("get to start.\n"); 104 goto istart; 105 } 106 printplayer(USER); 107 printf("get to start.\n"); 108 109 for (;;) { 110 move = usermove(); 111 if (!comphand[move]) { 112 if (gofish(move, USER, userhand)) 113 continue; 114 } else { 115 goodmove(USER, move, userhand, comphand); 116 continue; 117 } 118 119 istart: for (;;) { 120 move = compmove(); 121 if (!userhand[move]) { 122 if (!gofish(move, COMPUTER, comphand)) 123 break; 124 } else 125 goodmove(COMPUTER, move, comphand, userhand); 126 } 127 } 128 /* NOTREACHED */ 129 return (EXIT_FAILURE); 130 } 131 132 static int 133 usermove(void) 134 { 135 int n; 136 const char **p; 137 char buf[256]; 138 139 printf("\nYour hand is:"); 140 printhand(userhand); 141 142 for (;;) { 143 printf("You ask me for: "); 144 fflush(stdout); 145 if (fgets(buf, sizeof(buf), stdin) == NULL) 146 exit(0); 147 if (buf[0] == '\0') 148 continue; 149 if (buf[0] == '\n') { 150 printf("%d cards in my hand, %d in the pool.\n", 151 countcards(comphand), countcards(deck)); 152 printf("My books:"); 153 countbooks(comphand); 154 continue; 155 } 156 buf[strlen(buf) - 1] = '\0'; 157 if (!strcasecmp(buf, "p") && !promode) { 158 promode = 1; 159 printf("Entering pro mode.\n"); 160 continue; 161 } 162 if (!strcasecmp(buf, "quit")) 163 exit(0); 164 for (p = cards; *p; ++p) 165 if (!strcasecmp(*p, buf)) 166 break; 167 if (!*p) { 168 printf("I don't understand!\n"); 169 continue; 170 } 171 n = p - cards; 172 if (userhand[n] <= 3) { 173 userasked[n] = 1; 174 return(n); 175 } 176 if (userhand[n] == 4) { 177 printf("You already have all of those.\n"); 178 continue; 179 } 180 181 if (nrandom(3) == 1) 182 printf("You don't have any of those!\n"); 183 else 184 printf("You don't have any %s's!\n", cards[n]); 185 if (nrandom(4) == 1) 186 printf("No cheating!\n"); 187 printf("Guess again.\n"); 188 } 189 /* NOTREACHED */ 190 } 191 192 static int 193 compmove(void) 194 { 195 static int lmove; 196 197 if (promode) 198 lmove = promove(); 199 else { 200 do { 201 lmove = (lmove + 1) % RANKS; 202 } while (!comphand[lmove] || comphand[lmove] == CARDS); 203 } 204 asked[lmove] = 1; 205 206 printf("I ask you for: %s.\n", cards[lmove]); 207 return(lmove); 208 } 209 210 static int 211 promove(void) 212 { 213 int i, max; 214 215 for (i = 0; i < RANKS; ++i) 216 if (userasked[i] && comphand[i] > 0 && comphand[i] < CARDS) { 217 userasked[i] = 0; 218 return(i); 219 } 220 if (nrandom(3) == 1) { 221 for (i = 0;; ++i) 222 if (comphand[i] && comphand[i] != CARDS) { 223 max = i; 224 break; 225 } 226 while (++i < RANKS) 227 if (comphand[i] != CARDS && comphand[i] > comphand[max]) 228 max = i; 229 return(max); 230 } 231 if (nrandom(1024) == 0723) { 232 for (i = 0; i < RANKS; ++i) 233 if (userhand[i] && comphand[i]) 234 return(i); 235 } 236 for (;;) { 237 for (i = 0; i < RANKS; ++i) 238 if (comphand[i] && comphand[i] != CARDS && !asked[i]) 239 return(i); 240 for (i = 0; i < RANKS; ++i) 241 asked[i] = 0; 242 } 243 /* NOTREACHED */ 244 } 245 246 static int 247 drawcard(int player, int *hand) 248 { 249 int card; 250 251 while (deck[card = nrandom(RANKS)] == 0) 252 ; /* nothing */ 253 ++hand[card]; 254 --deck[card]; 255 if (player == USER || hand[card] == CARDS) { 256 printplayer(player); 257 printf("drew %s", cards[card]); 258 if (hand[card] == CARDS) { 259 printf(" and made a book of %s's!\n", cards[card]); 260 chkwinner(player, hand); 261 } else 262 printf(".\n"); 263 } 264 return(card); 265 } 266 267 static int 268 gofish(int askedfor, int player, int *hand) 269 { 270 printplayer(OTHER(player)); 271 printf("say \"GO FISH!\"\n"); 272 if (askedfor == drawcard(player, hand)) { 273 printplayer(player); 274 printf("drew the guess!\n"); 275 printplayer(player); 276 printf("get to ask again!\n"); 277 return(1); 278 } 279 return(0); 280 } 281 282 static void 283 goodmove(int player, int move, int *hand, int *opphand) 284 { 285 printplayer(OTHER(player)); 286 printf("have %d %s%s.\n", 287 opphand[move], cards[move], opphand[move] == 1 ? "": "'s"); 288 289 hand[move] += opphand[move]; 290 opphand[move] = 0; 291 292 if (hand[move] == CARDS) { 293 printplayer(player); 294 printf("made a book of %s's!\n", cards[move]); 295 chkwinner(player, hand); 296 } 297 298 chkwinner(OTHER(player), opphand); 299 300 printplayer(player); 301 printf("get another guess!\n"); 302 } 303 304 static void 305 chkwinner(int player, int *hand) 306 { 307 int cb, i, ub; 308 309 for (i = 0; i < RANKS; ++i) 310 if (hand[i] > 0 && hand[i] < CARDS) 311 return; 312 printplayer(player); 313 printf("don't have any more cards!\n"); 314 printf("My books:"); 315 cb = countbooks(comphand); 316 printf("Your books:"); 317 ub = countbooks(userhand); 318 printf("\nI have %d, you have %d.\n", cb, ub); 319 if (ub > cb) { 320 printf("\nYou win!!!\n"); 321 if (nrandom(1024) == 0723) 322 printf("Cheater, cheater, pumpkin eater!\n"); 323 } else if (cb > ub) { 324 printf("\nI win!!!\n"); 325 if (nrandom(1024) == 0723) 326 printf("Hah! Stupid peasant!\n"); 327 } else 328 printf("\nTie!\n"); 329 exit(0); 330 } 331 332 static void 333 printplayer(int player) 334 { 335 switch (player) { 336 case COMPUTER: 337 printf("I "); 338 break; 339 case USER: 340 printf("You "); 341 break; 342 } 343 } 344 345 static void 346 printhand(int *hand) 347 { 348 int book, i, j; 349 350 for (book = i = 0; i < RANKS; i++) 351 if (hand[i] < CARDS) 352 for (j = hand[i]; --j >= 0;) 353 PRC(i); 354 else 355 ++book; 356 if (book) { 357 printf(" + Book%s of", book > 1 ? "s" : ""); 358 for (i = 0; i < RANKS; i++) 359 if (hand[i] == CARDS) 360 PRC(i); 361 } 362 putchar('\n'); 363 } 364 365 static int 366 countcards(int *hand) 367 { 368 int i, count; 369 370 for (count = i = 0; i < RANKS; i++) 371 count += *hand++; 372 return(count); 373 } 374 375 static int 376 countbooks(int *hand) 377 { 378 int i, count; 379 380 for (count = i = 0; i < RANKS; i++) 381 if (hand[i] == CARDS) { 382 ++count; 383 PRC(i); 384 } 385 if (!count) 386 printf(" none"); 387 putchar('\n'); 388 return(count); 389 } 390 391 static void 392 init(void) 393 { 394 int i, rank; 395 396 for (i = 0; i < RANKS; ++i) 397 deck[i] = CARDS; 398 for (i = 0; i < HANDSIZE; ++i) { 399 while (!deck[rank = nrandom(RANKS)]) 400 ; /* nothing */ 401 ++userhand[rank]; 402 --deck[rank]; 403 } 404 for (i = 0; i < HANDSIZE; ++i) { 405 while (!deck[rank = nrandom(RANKS)]) 406 ; /* nothing */ 407 ++comphand[rank]; 408 --deck[rank]; 409 } 410 } 411 412 static int 413 nrandom(int n) 414 { 415 416 return((int)random() % n); 417 } 418 419 static void 420 instructions(void) 421 { 422 int input; 423 char buf[1024]; 424 425 printf("Would you like instructions (y or n)? "); 426 input = getchar(); 427 while (getchar() != '\n'); 428 if (input != 'y') 429 return; 430 431 sprintf(buf, "%s %s", _PATH_MORE, _PATH_INSTR); 432 system(buf); 433 printf("Hit return to continue...\n"); 434 while ((input = getchar()) != EOF && input != '\n'); 435 } 436 437 static void 438 usage(void) 439 { 440 fprintf(stderr, "usage: fish [-p]\n"); 441 exit(1); 442 } 443