Home | History | Annotate | Line # | Download | only in fish
fish.c revision 1.14
      1 /*	$NetBSD: fish.c,v 1.14 2003/08/07 09:37:13 agc 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\n\
     38 	The Regents of the University of California.  All rights reserved.\n");
     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.14 2003/08/07 09:37:13 agc 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 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 int promode;
     77 int asked[RANKS], comphand[RANKS], deck[TOTCARDS];
     78 int userasked[RANKS], userhand[RANKS];
     79 int curcard = TOTCARDS;
     80 
     81 void	chkwinner __P((int, const int *));
     82 int	compmove __P((void));
     83 int	countbooks __P((const int *));
     84 int	countcards __P((const int *));
     85 int	drawcard __P((int, int *));
     86 int	gofish __P((int, int, int *));
     87 void	goodmove __P((int, int, int *, int *));
     88 void	init __P((void));
     89 void	instructions __P((void));
     90 int	main __P((int, char *[]));
     91 int	nrandom __P((int));
     92 void	printhand __P((const int *));
     93 void	printplayer __P((int));
     94 int	promove __P((void));
     95 void	usage __P((void)) __attribute__((__noreturn__));
     96 int	usermove __P((void));
     97 
     98 int
     99 main(argc, argv)
    100 	int argc;
    101 	char **argv;
    102 {
    103 	int ch, move;
    104 
    105 	/* Revoke setgid privileges */
    106 	setgid(getgid());
    107 
    108 	while ((ch = getopt(argc, argv, "p")) != -1)
    109 		switch(ch) {
    110 		case 'p':
    111 			promode = 1;
    112 			break;
    113 		case '?':
    114 		default:
    115 			usage();
    116 		}
    117 
    118 	srandom(time((time_t *)NULL));
    119 	instructions();
    120 	init();
    121 
    122 	if (nrandom(2) == 1) {
    123 		printplayer(COMPUTER);
    124 		(void)printf("get to start.\n");
    125 		goto istart;
    126 	}
    127 	printplayer(USER);
    128 	(void)printf("get to start.\n");
    129 
    130 	for (;;) {
    131 		move = usermove();
    132 		if (!comphand[move]) {
    133 			if (gofish(move, USER, userhand))
    134 				continue;
    135 		} else {
    136 			goodmove(USER, move, userhand, comphand);
    137 			continue;
    138 		}
    139 
    140 istart:		for (;;) {
    141 			move = compmove();
    142 			if (!userhand[move]) {
    143 				if (!gofish(move, COMPUTER, comphand))
    144 					break;
    145 			} else
    146 				goodmove(COMPUTER, move, comphand, userhand);
    147 		}
    148 	}
    149 	/* NOTREACHED */
    150 }
    151 
    152 int
    153 usermove()
    154 {
    155 	int n;
    156 	const char *const *p;
    157 	char buf[256];
    158 
    159 	(void)printf("\nYour hand is:");
    160 	printhand(userhand);
    161 
    162 	for (;;) {
    163 		(void)printf("You ask me for: ");
    164 		(void)fflush(stdout);
    165 		if (fgets(buf, sizeof(buf), stdin) == NULL)
    166 			exit(0);
    167 		if (buf[0] == '\0')
    168 			continue;
    169 		if (buf[0] == '\n') {
    170 			(void)printf("%d cards in my hand, %d in the pool.\n",
    171 			    countcards(comphand), curcard);
    172 			(void)printf("My books:");
    173 			(void)countbooks(comphand);
    174 			continue;
    175 		}
    176 		buf[strlen(buf) - 1] = '\0';
    177 		if (!strcasecmp(buf, "p") && !promode) {
    178 			promode = 1;
    179 			(void)printf("Entering pro mode.\n");
    180 			continue;
    181 		}
    182 		if (!strcasecmp(buf, "quit"))
    183 			exit(0);
    184 		for (p = cards; *p; ++p)
    185 			if (!strcasecmp(*p, buf))
    186 				break;
    187 		if (!*p) {
    188 			(void)printf("I don't understand!\n");
    189 			continue;
    190 		}
    191 		n = p - cards;
    192 		if (userhand[n]) {
    193 			userasked[n] = 1;
    194 			return(n);
    195 		}
    196 		if (nrandom(3) == 1)
    197 			(void)printf("You don't have any of those!\n");
    198 		else
    199 			(void)printf("You don't have any %s's!\n", cards[n]);
    200 		if (nrandom(4) == 1)
    201 			(void)printf("No cheating!\n");
    202 		(void)printf("Guess again.\n");
    203 	}
    204 	/* NOTREACHED */
    205 }
    206 
    207 int
    208 compmove()
    209 {
    210 	static int lmove;
    211 
    212 	if (promode)
    213 		lmove = promove();
    214 	else {
    215 		do {
    216 			lmove = (lmove + 1) % RANKS;
    217 		} while (!comphand[lmove] || comphand[lmove] == CARDS);
    218 	}
    219 	asked[lmove] = 1;
    220 
    221 	(void)printf("I ask you for: %s.\n", cards[lmove]);
    222 	return(lmove);
    223 }
    224 
    225 int
    226 promove()
    227 {
    228 	int i, max;
    229 
    230 	for (i = 0; i < RANKS; ++i)
    231 		if (userasked[i] &&
    232 		    comphand[i] > 0 && comphand[i] < CARDS) {
    233 			userasked[i] = 0;
    234 			return(i);
    235 		}
    236 	if (nrandom(3) == 1) {
    237 		for (i = 0;; ++i)
    238 			if (comphand[i] && comphand[i] != CARDS) {
    239 				max = i;
    240 				break;
    241 			}
    242 		while (++i < RANKS)
    243 			if (comphand[i] != CARDS &&
    244 			    comphand[i] > comphand[max])
    245 				max = i;
    246 		return(max);
    247 	}
    248 	if (nrandom(1024) == 0723) {
    249 		for (i = 0; i < RANKS; ++i)
    250 			if (userhand[i] && comphand[i])
    251 				return(i);
    252 	}
    253 	for (;;) {
    254 		for (i = 0; i < RANKS; ++i)
    255 			if (comphand[i] && comphand[i] != CARDS &&
    256 			    !asked[i])
    257 				return(i);
    258 		for (i = 0; i < RANKS; ++i)
    259 			asked[i] = 0;
    260 	}
    261 	/* NOTREACHED */
    262 }
    263 
    264 int
    265 drawcard(player, hand)
    266 	int player;
    267 	int *hand;
    268 {
    269 	int card;
    270 
    271 	++hand[card = deck[--curcard]];
    272 	if (player == USER || hand[card] == CARDS) {
    273 		printplayer(player);
    274 		(void)printf("drew %s", cards[card]);
    275 		if (hand[card] == CARDS) {
    276 			(void)printf(" and made a book of %s's!\n",
    277 			     cards[card]);
    278 			chkwinner(player, hand);
    279 		} else
    280 			(void)printf(".\n");
    281 	}
    282 	return(card);
    283 }
    284 
    285 int
    286 gofish(askedfor, player, hand)
    287 	int askedfor, player;
    288 	int *hand;
    289 {
    290 	printplayer(OTHER(player));
    291 	(void)printf("say \"GO FISH!\"\n");
    292 	if (askedfor == drawcard(player, hand)) {
    293 		printplayer(player);
    294 		(void)printf("drew the guess!\n");
    295 		printplayer(player);
    296 		(void)printf("get to ask again!\n");
    297 		return(1);
    298 	}
    299 	return(0);
    300 }
    301 
    302 void
    303 goodmove(player, move, hand, opphand)
    304 	int player, move;
    305 	int *hand, *opphand;
    306 {
    307 	printplayer(OTHER(player));
    308 	(void)printf("have %d %s%s.\n",
    309 	    opphand[move], cards[move], opphand[move] == 1 ? "": "'s");
    310 
    311 	hand[move] += opphand[move];
    312 	opphand[move] = 0;
    313 
    314 	if (hand[move] == CARDS) {
    315 		printplayer(player);
    316 		(void)printf("made a book of %s's!\n", cards[move]);
    317 		chkwinner(player, hand);
    318 	}
    319 
    320 	chkwinner(OTHER(player), opphand);
    321 
    322 	printplayer(player);
    323 	(void)printf("get another guess!\n");
    324 }
    325 
    326 void
    327 chkwinner(player, hand)
    328 	int player;
    329 	const int *hand;
    330 {
    331 	int cb, i, ub;
    332 
    333 	for (i = 0; i < RANKS; ++i)
    334 		if (hand[i] > 0 && hand[i] < CARDS)
    335 			return;
    336 	printplayer(player);
    337 	(void)printf("don't have any more cards!\n");
    338 	(void)printf("My books:");
    339 	cb = countbooks(comphand);
    340 	(void)printf("Your books:");
    341 	ub = countbooks(userhand);
    342 	(void)printf("\nI have %d, you have %d.\n", cb, ub);
    343 	if (ub > cb) {
    344 		(void)printf("\nYou win!!!\n");
    345 		if (nrandom(1024) == 0723)
    346 			(void)printf("Cheater, cheater, pumpkin eater!\n");
    347 	} else if (cb > ub) {
    348 		(void)printf("\nI win!!!\n");
    349 		if (nrandom(1024) == 0723)
    350 			(void)printf("Hah!  Stupid peasant!\n");
    351 	} else
    352 		(void)printf("\nTie!\n");
    353 	exit(0);
    354 }
    355 
    356 void
    357 printplayer(player)
    358 	int player;
    359 {
    360 	switch (player) {
    361 	case COMPUTER:
    362 		(void)printf("I ");
    363 		break;
    364 	case USER:
    365 		(void)printf("You ");
    366 		break;
    367 	}
    368 }
    369 
    370 void
    371 printhand(hand)
    372 	const int *hand;
    373 {
    374 	int book, i, j;
    375 
    376 	for (book = i = 0; i < RANKS; i++)
    377 		if (hand[i] < CARDS)
    378 			for (j = hand[i]; --j >= 0;)
    379 				PRC(i);
    380 		else
    381 			++book;
    382 	if (book) {
    383 		(void)printf(" + Book%s of", book > 1 ? "s" : "");
    384 		for (i = 0; i < RANKS; i++)
    385 			if (hand[i] == CARDS)
    386 				PRC(i);
    387 	}
    388 	(void)putchar('\n');
    389 }
    390 
    391 int
    392 countcards(hand)
    393 	const int *hand;
    394 {
    395 	int i, count;
    396 
    397 	for (count = i = 0; i < RANKS; i++)
    398 		count += *hand++;
    399 	return(count);
    400 }
    401 
    402 int
    403 countbooks(hand)
    404 	const int *hand;
    405 {
    406 	int i, count;
    407 
    408 	for (count = i = 0; i < RANKS; i++)
    409 		if (hand[i] == CARDS) {
    410 			++count;
    411 			PRC(i);
    412 		}
    413 	if (!count)
    414 		(void)printf(" none");
    415 	(void)putchar('\n');
    416 	return(count);
    417 }
    418 
    419 void
    420 init()
    421 {
    422 	int i, j, temp;
    423 
    424 	for (i = 0; i < TOTCARDS; ++i)
    425 		deck[i] = i % RANKS;
    426 	for (i = 0; i < TOTCARDS - 1; ++i) {
    427 		j = nrandom(TOTCARDS-i);
    428 		if (j == 0)
    429 			continue;
    430 		temp = deck[i];
    431 		deck[i] = deck[i+j];
    432 		deck[i+j] = temp;
    433 	}
    434 	for (i = 0; i < HANDSIZE; ++i) {
    435 		++userhand[deck[--curcard]];
    436 		++comphand[deck[--curcard]];
    437 	}
    438 }
    439 
    440 int
    441 nrandom(n)
    442 	int n;
    443 {
    444 
    445 	return((int)random() % n);
    446 }
    447 
    448 void
    449 instructions()
    450 {
    451 	int input;
    452 	pid_t pid;
    453 	int fd;
    454 	const char *pager;
    455 	int status;
    456 
    457 	(void)printf("Would you like instructions (y or n)? ");
    458 	input = getchar();
    459 	while (getchar() != '\n');
    460 	if (input != 'y')
    461 		return;
    462 
    463 	switch (pid = fork()) {
    464 	case 0: /* child */
    465 		if (!isatty(1))
    466 			pager = "cat";
    467 		else {
    468 			if (!(pager = getenv("PAGER")) || (*pager == 0))
    469 				pager = _PATH_MORE;
    470 		}
    471 		if ((fd = open(_PATH_INSTR, O_RDONLY)) == -1)
    472 			err(1, "open %s", _PATH_INSTR);
    473 		if (dup2(fd, 0) == -1)
    474 			err(1, "dup2");
    475 		(void)execl("/bin/sh", "sh", "-c", pager, NULL);
    476 		err(1, "exec sh -c %s", pager);
    477 		/*NOTREACHED*/
    478 	case -1:
    479 		err(1, "fork");
    480 		/*NOTREACHED*/
    481 	default:
    482 		(void)waitpid(pid, &status, 0);
    483 		break;
    484 	}
    485 	(void)printf("Hit return to continue...\n");
    486 	while ((input = getchar()) != EOF && input != '\n');
    487 }
    488 
    489 void
    490 usage()
    491 {
    492 	(void)fprintf(stderr, "usage: fish [-p]\n");
    493 	exit(1);
    494 }
    495