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