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