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]) { 173 userasked[n] = 1; 174 return(n); 175 } 176 if (nrandom(3) == 1) 177 printf("You don't have any of those!\n"); 178 else 179 printf("You don't have any %s's!\n", cards[n]); 180 if (nrandom(4) == 1) 181 printf("No cheating!\n"); 182 printf("Guess again.\n"); 183 } 184 /* NOTREACHED */ 185 } 186 187 static int 188 compmove(void) 189 { 190 static int lmove; 191 192 if (promode) 193 lmove = promove(); 194 else { 195 do { 196 lmove = (lmove + 1) % RANKS; 197 } while (!comphand[lmove] || comphand[lmove] == CARDS); 198 } 199 asked[lmove] = 1; 200 201 printf("I ask you for: %s.\n", cards[lmove]); 202 return(lmove); 203 } 204 205 static int 206 promove(void) 207 { 208 int i, max; 209 210 for (i = 0; i < RANKS; ++i) 211 if (userasked[i] && comphand[i] > 0 && comphand[i] < CARDS) { 212 userasked[i] = 0; 213 return(i); 214 } 215 if (nrandom(3) == 1) { 216 for (i = 0;; ++i) 217 if (comphand[i] && comphand[i] != CARDS) { 218 max = i; 219 break; 220 } 221 while (++i < RANKS) 222 if (comphand[i] != CARDS && comphand[i] > comphand[max]) 223 max = i; 224 return(max); 225 } 226 if (nrandom(1024) == 0723) { 227 for (i = 0; i < RANKS; ++i) 228 if (userhand[i] && comphand[i]) 229 return(i); 230 } 231 for (;;) { 232 for (i = 0; i < RANKS; ++i) 233 if (comphand[i] && comphand[i] != CARDS && !asked[i]) 234 return(i); 235 for (i = 0; i < RANKS; ++i) 236 asked[i] = 0; 237 } 238 /* NOTREACHED */ 239 } 240 241 static int 242 drawcard(int player, int *hand) 243 { 244 int card; 245 246 while (deck[card = nrandom(RANKS)] == 0) 247 ; /* nothing */ 248 ++hand[card]; 249 --deck[card]; 250 if (player == USER || hand[card] == CARDS) { 251 printplayer(player); 252 printf("drew %s", cards[card]); 253 if (hand[card] == CARDS) { 254 printf(" and made a book of %s's!\n", cards[card]); 255 chkwinner(player, hand); 256 } else 257 printf(".\n"); 258 } 259 return(card); 260 } 261 262 static int 263 gofish(int askedfor, int player, int *hand) 264 { 265 printplayer(OTHER(player)); 266 printf("say \"GO FISH!\"\n"); 267 if (askedfor == drawcard(player, hand)) { 268 printplayer(player); 269 printf("drew the guess!\n"); 270 printplayer(player); 271 printf("get to ask again!\n"); 272 return(1); 273 } 274 return(0); 275 } 276 277 static void 278 goodmove(int player, int move, int *hand, int *opphand) 279 { 280 printplayer(OTHER(player)); 281 printf("have %d %s%s.\n", 282 opphand[move], cards[move], opphand[move] == 1 ? "": "'s"); 283 284 hand[move] += opphand[move]; 285 opphand[move] = 0; 286 287 if (hand[move] == CARDS) { 288 printplayer(player); 289 printf("made a book of %s's!\n", cards[move]); 290 chkwinner(player, hand); 291 } 292 293 chkwinner(OTHER(player), opphand); 294 295 printplayer(player); 296 printf("get another guess!\n"); 297 } 298 299 static void 300 chkwinner(int player, int *hand) 301 { 302 int cb, i, ub; 303 304 for (i = 0; i < RANKS; ++i) 305 if (hand[i] > 0 && hand[i] < CARDS) 306 return; 307 printplayer(player); 308 printf("don't have any more cards!\n"); 309 printf("My books:"); 310 cb = countbooks(comphand); 311 printf("Your books:"); 312 ub = countbooks(userhand); 313 printf("\nI have %d, you have %d.\n", cb, ub); 314 if (ub > cb) { 315 printf("\nYou win!!!\n"); 316 if (nrandom(1024) == 0723) 317 printf("Cheater, cheater, pumpkin eater!\n"); 318 } else if (cb > ub) { 319 printf("\nI win!!!\n"); 320 if (nrandom(1024) == 0723) 321 printf("Hah! Stupid peasant!\n"); 322 } else 323 printf("\nTie!\n"); 324 exit(0); 325 } 326 327 static void 328 printplayer(int player) 329 { 330 switch (player) { 331 case COMPUTER: 332 printf("I "); 333 break; 334 case USER: 335 printf("You "); 336 break; 337 } 338 } 339 340 static void 341 printhand(int *hand) 342 { 343 int book, i, j; 344 345 for (book = i = 0; i < RANKS; i++) 346 if (hand[i] < CARDS) 347 for (j = hand[i]; --j >= 0;) 348 PRC(i); 349 else 350 ++book; 351 if (book) { 352 printf(" + Book%s of", book > 1 ? "s" : ""); 353 for (i = 0; i < RANKS; i++) 354 if (hand[i] == CARDS) 355 PRC(i); 356 } 357 putchar('\n'); 358 } 359 360 static int 361 countcards(int *hand) 362 { 363 int i, count; 364 365 for (count = i = 0; i < RANKS; i++) 366 count += *hand++; 367 return(count); 368 } 369 370 static int 371 countbooks(int *hand) 372 { 373 int i, count; 374 375 for (count = i = 0; i < RANKS; i++) 376 if (hand[i] == CARDS) { 377 ++count; 378 PRC(i); 379 } 380 if (!count) 381 printf(" none"); 382 putchar('\n'); 383 return(count); 384 } 385 386 static void 387 init(void) 388 { 389 int i, rank; 390 391 for (i = 0; i < RANKS; ++i) 392 deck[i] = CARDS; 393 for (i = 0; i < HANDSIZE; ++i) { 394 while (!deck[rank = nrandom(RANKS)]) 395 ; /* nothing */ 396 ++userhand[rank]; 397 --deck[rank]; 398 } 399 for (i = 0; i < HANDSIZE; ++i) { 400 while (!deck[rank = nrandom(RANKS)]) 401 ; /* nothing */ 402 ++comphand[rank]; 403 --deck[rank]; 404 } 405 } 406 407 static int 408 nrandom(int n) 409 { 410 411 return((int)random() % n); 412 } 413 414 static void 415 instructions(void) 416 { 417 int input; 418 char buf[1024]; 419 420 printf("Would you like instructions (y or n)? "); 421 input = getchar(); 422 while (getchar() != '\n'); 423 if (input != 'y') 424 return; 425 426 sprintf(buf, "%s %s", _PATH_MORE, _PATH_INSTR); 427 system(buf); 428 printf("Hit return to continue...\n"); 429 while ((input = getchar()) != EOF && input != '\n'); 430 } 431 432 static void 433 usage(void) 434 { 435 fprintf(stderr, "usage: fish [-p]\n"); 436 exit(1); 437 } 438