Home | History | Annotate | Line # | Download | only in fish
fish.c revision 1.22
      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