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