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 * 34 * @(#) Copyright (c) 1990, 1993 The Regents of the University of California. All rights reserved. 35 * @(#)fish.c 8.1 (Berkeley) 5/31/93 36 */ 37 38 #include <sys/types.h> 39 #include <errno.h> 40 #include <fcntl.h> 41 #include <spawn.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 static 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 static int promode; 63 static int asked[RANKS], comphand[RANKS], deck[RANKS]; 64 static int userasked[RANKS], userhand[RANKS]; 65 66 extern char **environ; 67 68 static void chkwinner(int, int *); 69 static int compmove(void); 70 static int countbooks(int *); 71 static int countcards(int *); 72 static int drawcard(int, int *); 73 static int gofish(int, int, int *); 74 static void goodmove(int, int, int *, int *); 75 static void init(void); 76 static void instructions(void); 77 static int nrandom(int); 78 static void printhand(int *); 79 static void printplayer(int); 80 static int promove(void); 81 static void usage(void) __dead2; 82 static int usermove(void); 83 84 int 85 main(int argc, char **argv) 86 { 87 int ch, move; 88 89 while ((ch = getopt(argc, argv, "p")) != -1) 90 switch(ch) { 91 case 'p': 92 promode = 1; 93 break; 94 case '?': 95 default: 96 usage(); 97 } 98 99 srandomdev(); 100 instructions(); 101 init(); 102 103 if (nrandom(2) == 1) { 104 printplayer(COMPUTER); 105 printf("get to start.\n"); 106 goto istart; 107 } 108 printplayer(USER); 109 printf("get to start.\n"); 110 111 for (;;) { 112 move = usermove(); 113 if (!comphand[move]) { 114 if (gofish(move, USER, userhand)) 115 continue; 116 } else { 117 goodmove(USER, move, userhand, comphand); 118 continue; 119 } 120 121 istart: for (;;) { 122 move = compmove(); 123 if (!userhand[move]) { 124 if (!gofish(move, COMPUTER, comphand)) 125 break; 126 } else 127 goodmove(COMPUTER, move, comphand, userhand); 128 } 129 } 130 /* NOTREACHED */ 131 return (EXIT_FAILURE); 132 } 133 134 static int 135 usermove(void) 136 { 137 int n; 138 const char **p; 139 char buf[256]; 140 141 printf("\nYour hand is:"); 142 printhand(userhand); 143 144 for (;;) { 145 printf("You ask me for: "); 146 fflush(stdout); 147 if (fgets(buf, sizeof(buf), stdin) == NULL) 148 exit(0); 149 if (buf[0] == '\0') 150 continue; 151 if (buf[0] == '\n') { 152 printf("%d cards in my hand, %d in the pool.\n", 153 countcards(comphand), countcards(deck)); 154 printf("My books:"); 155 countbooks(comphand); 156 continue; 157 } 158 buf[strlen(buf) - 1] = '\0'; 159 if (!strcasecmp(buf, "p")) { 160 if (promode) { 161 printf("Already in pro mode.\n"); 162 } else { 163 printf("Entering pro mode.\n"); 164 promode = 1; 165 } 166 continue; 167 } 168 if (!strcasecmp(buf, "quit")) 169 exit(0); 170 for (p = cards; *p; ++p) 171 if (!strcasecmp(*p, buf)) 172 break; 173 if (!*p) { 174 printf("I don't understand!\n"); 175 continue; 176 } 177 n = p - cards; 178 if (userhand[n] <= 3 && userhand[n]) { 179 userasked[n] = 1; 180 return(n); 181 } 182 if (userhand[n] == 4) { 183 printf("You already have all of those.\n"); 184 continue; 185 } 186 187 if (nrandom(3) == 1) 188 printf("You don't have any of those!\n"); 189 else 190 printf("You don't have any %s's!\n", cards[n]); 191 if (nrandom(4) == 1) 192 printf("No cheating!\n"); 193 printf("Guess again.\n"); 194 } 195 /* NOTREACHED */ 196 } 197 198 static int 199 compmove(void) 200 { 201 static int lmove; 202 203 if (promode) 204 lmove = promove(); 205 else { 206 do { 207 lmove = (lmove + 1) % RANKS; 208 } while (!comphand[lmove] || comphand[lmove] == CARDS); 209 } 210 asked[lmove] = 1; 211 212 printf("I ask you for: %s.\n", cards[lmove]); 213 return(lmove); 214 } 215 216 static int 217 promove(void) 218 { 219 int i, max; 220 221 for (i = 0; i < RANKS; ++i) 222 if (userasked[i] && comphand[i] > 0 && comphand[i] < CARDS) { 223 userasked[i] = 0; 224 return(i); 225 } 226 if (nrandom(3) == 1) { 227 for (i = 0;; ++i) 228 if (comphand[i] && comphand[i] != CARDS) { 229 max = i; 230 break; 231 } 232 while (++i < RANKS) 233 if (comphand[i] != CARDS && comphand[i] > comphand[max]) 234 max = i; 235 return(max); 236 } 237 if (nrandom(1024) == 0723) { 238 for (i = 0; i < RANKS; ++i) 239 if (userhand[i] && comphand[i]) 240 return(i); 241 } 242 for (;;) { 243 for (i = 0; i < RANKS; ++i) 244 if (comphand[i] && comphand[i] != CARDS && !asked[i]) 245 return(i); 246 for (i = 0; i < RANKS; ++i) 247 asked[i] = 0; 248 } 249 /* NOTREACHED */ 250 } 251 252 static int 253 drawcard(int player, int *hand) 254 { 255 int card; 256 257 while (deck[card = nrandom(RANKS)] == 0) 258 ; /* nothing */ 259 ++hand[card]; 260 --deck[card]; 261 if (player == USER || hand[card] == CARDS) { 262 printplayer(player); 263 printf("drew %s", cards[card]); 264 if (hand[card] == CARDS) { 265 printf(" and made a book of %s's!\n", cards[card]); 266 chkwinner(player, hand); 267 } else 268 printf(".\n"); 269 } 270 return(card); 271 } 272 273 static int 274 gofish(int askedfor, int player, int *hand) 275 { 276 printplayer(OTHER(player)); 277 printf("say \"GO FISH!\"\n"); 278 if (askedfor == drawcard(player, hand)) { 279 printplayer(player); 280 printf("drew the guess!\n"); 281 printplayer(player); 282 printf("get to ask again!\n"); 283 return(1); 284 } 285 return(0); 286 } 287 288 static void 289 goodmove(int player, int move, int *hand, int *opphand) 290 { 291 printplayer(OTHER(player)); 292 printf("have %d %s%s.\n", 293 opphand[move], cards[move], opphand[move] == 1 ? "": "'s"); 294 295 hand[move] += opphand[move]; 296 opphand[move] = 0; 297 298 if (hand[move] == CARDS) { 299 printplayer(player); 300 printf("made a book of %s's!\n", cards[move]); 301 chkwinner(player, hand); 302 } 303 304 chkwinner(OTHER(player), opphand); 305 306 printplayer(player); 307 printf("get another guess!\n"); 308 } 309 310 static void 311 chkwinner(int player, int *hand) 312 { 313 int cb, i, ub; 314 315 for (i = 0; i < RANKS; ++i) 316 if (hand[i] > 0 && hand[i] < CARDS) 317 return; 318 printplayer(player); 319 printf("don't have any more cards!\n"); 320 printf("My books:"); 321 cb = countbooks(comphand); 322 printf("Your books:"); 323 ub = countbooks(userhand); 324 printf("\nI have %d, you have %d.\n", cb, ub); 325 if (ub > cb) { 326 printf("\nYou win!!!\n"); 327 if (nrandom(1024) == 0723) 328 printf("Cheater, cheater, pumpkin eater!\n"); 329 } else if (cb > ub) { 330 printf("\nI win!!!\n"); 331 if (nrandom(1024) == 0723) 332 printf("Hah! Stupid peasant!\n"); 333 } else 334 printf("\nTie!\n"); 335 exit(0); 336 } 337 338 static void 339 printplayer(int player) 340 { 341 switch (player) { 342 case COMPUTER: 343 printf("I "); 344 break; 345 case USER: 346 printf("You "); 347 break; 348 } 349 } 350 351 static void 352 printhand(int *hand) 353 { 354 int book, i, j; 355 356 for (book = i = 0; i < RANKS; i++) 357 if (hand[i] < CARDS) 358 for (j = hand[i]; --j >= 0;) 359 PRC(i); 360 else 361 ++book; 362 if (book) { 363 printf(" + Book%s of", book > 1 ? "s" : ""); 364 for (i = 0; i < RANKS; i++) 365 if (hand[i] == CARDS) 366 PRC(i); 367 } 368 putchar('\n'); 369 } 370 371 static int 372 countcards(int *hand) 373 { 374 int i, count; 375 376 for (count = i = 0; i < RANKS; i++) 377 count += *hand++; 378 return(count); 379 } 380 381 static int 382 countbooks(int *hand) 383 { 384 int i, count; 385 386 for (count = i = 0; i < RANKS; i++) 387 if (hand[i] == CARDS) { 388 ++count; 389 PRC(i); 390 } 391 if (!count) 392 printf(" none"); 393 putchar('\n'); 394 return(count); 395 } 396 397 static void 398 init(void) 399 { 400 int i, rank; 401 402 for (i = 0; i < RANKS; ++i) 403 deck[i] = CARDS; 404 for (i = 0; i < HANDSIZE; ++i) { 405 while (!deck[rank = nrandom(RANKS)]) 406 ; /* nothing */ 407 ++userhand[rank]; 408 --deck[rank]; 409 } 410 for (i = 0; i < HANDSIZE; ++i) { 411 while (!deck[rank = nrandom(RANKS)]) 412 ; /* nothing */ 413 ++comphand[rank]; 414 --deck[rank]; 415 } 416 } 417 418 static int 419 nrandom(int n) 420 { 421 422 return((int)random() % n); 423 } 424 425 static void 426 instructions(void) 427 { 428 int input, status, pid; 429 const char * const argv[] = {PATH_PAGER, PATH_INSTR, NULL}; 430 431 printf("Would you like instructions (y or n)? "); 432 input = getchar(); 433 while (getchar() != '\n'); 434 if (input != 'y') 435 return; 436 437 status = posix_spawnp(&pid, PATH_PAGER, NULL, NULL, 438 __DECONST(char * const *, argv), environ); 439 if (status != 0) { 440 printf("Unable to spawn %s\n",PATH_PAGER); 441 } 442 printf("Hit return to continue...\n"); 443 while ((input = getchar()) != EOF && input != '\n'); 444 } 445 446 static void 447 usage(void) 448 { 449 fprintf(stderr, "usage: fish [-p]\n"); 450 exit(1); 451 } 452