Home | History | Annotate | Line # | Download | only in fish
fish.c revision 1.8
      1 /*	$NetBSD: fish.c,v 1.8 1999/07/14 17:30:21 hubertf 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.8 1999/07/14 17:30:21 hubertf 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 
     69 #define	USER		1
     70 #define	COMPUTER	0
     71 #define	OTHER(a)	(1 - (a))
     72 
     73 char *cards[] = {
     74 	"A", "2", "3", "4", "5", "6", "7",
     75 	"8", "9", "10", "J", "Q", "K", NULL,
     76 };
     77 #define	PRC(card)	(void)printf(" %s", cards[card])
     78 
     79 int promode;
     80 int asked[RANKS], comphand[RANKS], deck[RANKS];
     81 int userasked[RANKS], userhand[RANKS];
     82 
     83 void	chkwinner __P((int, int *));
     84 int	compmove __P((void));
     85 int	countbooks __P((int *));
     86 int	countcards __P((int *));
     87 int	drawcard __P((int, int *));
     88 int	gofish __P((int, int, int *));
     89 void	goodmove __P((int, int, int *, int *));
     90 void	init __P((void));
     91 void	instructions __P((void));
     92 int	main __P((int, char *[]));
     93 int	nrandom __P((int));
     94 void	printhand __P((int *));
     95 void	printplayer __P((int));
     96 int	promove __P((void));
     97 void	usage __P((void)) __attribute__((__noreturn__));
     98 int	usermove __P((void));
     99 
    100 int
    101 main(argc, argv)
    102 	int argc;
    103 	char **argv;
    104 {
    105 	int ch, move;
    106 
    107 	setgid(getgid());
    108 
    109 	while ((ch = getopt(argc, argv, "p")) != -1)
    110 		switch(ch) {
    111 		case 'p':
    112 			promode = 1;
    113 			break;
    114 		case '?':
    115 		default:
    116 			(void)fprintf(stderr, "usage: fish [-p]\n");
    117 			exit(1);
    118 		}
    119 
    120 	srandom(time((time_t *)NULL));
    121 	instructions();
    122 	init();
    123 
    124 	if (nrandom(2) == 1) {
    125 		printplayer(COMPUTER);
    126 		(void)printf("get to start.\n");
    127 		goto istart;
    128 	}
    129 	printplayer(USER);
    130 	(void)printf("get to start.\n");
    131 
    132 	for (;;) {
    133 		move = usermove();
    134 		if (!comphand[move]) {
    135 			if (gofish(move, USER, userhand))
    136 				continue;
    137 		} else {
    138 			goodmove(USER, move, userhand, comphand);
    139 			continue;
    140 		}
    141 
    142 istart:		for (;;) {
    143 			move = compmove();
    144 			if (!userhand[move]) {
    145 				if (!gofish(move, COMPUTER, comphand))
    146 					break;
    147 			} else
    148 				goodmove(COMPUTER, move, comphand, userhand);
    149 		}
    150 	}
    151 	/* NOTREACHED */
    152 }
    153 
    154 int
    155 usermove()
    156 {
    157 	int n;
    158 	char **p;
    159 	char buf[256];
    160 
    161 	(void)printf("\nYour hand is:");
    162 	printhand(userhand);
    163 
    164 	for (;;) {
    165 		(void)printf("You ask me for: ");
    166 		(void)fflush(stdout);
    167 		if (fgets(buf, sizeof(buf), stdin) == NULL)
    168 			exit(0);
    169 		if (buf[0] == '\0')
    170 			continue;
    171 		if (buf[0] == '\n') {
    172 			(void)printf("%d cards in my hand, %d in the pool.\n",
    173 			    countcards(comphand), countcards(deck));
    174 			(void)printf("My books:");
    175 			(void)countbooks(comphand);
    176 			continue;
    177 		}
    178 		buf[strlen(buf) - 1] = '\0';
    179 		if (!strcasecmp(buf, "p") && !promode) {
    180 			promode = 1;
    181 			(void)printf("Entering pro mode.\n");
    182 			continue;
    183 		}
    184 		if (!strcasecmp(buf, "quit"))
    185 			exit(0);
    186 		for (p = cards; *p; ++p)
    187 			if (!strcasecmp(*p, buf))
    188 				break;
    189 		if (!*p) {
    190 			(void)printf("I don't understand!\n");
    191 			continue;
    192 		}
    193 		n = p - cards;
    194 		if (userhand[n]) {
    195 			userasked[n] = 1;
    196 			return(n);
    197 		}
    198 		if (nrandom(3) == 1)
    199 			(void)printf("You don't have any of those!\n");
    200 		else
    201 			(void)printf("You don't have any %s's!\n", cards[n]);
    202 		if (nrandom(4) == 1)
    203 			(void)printf("No cheating!\n");
    204 		(void)printf("Guess again.\n");
    205 	}
    206 	/* NOTREACHED */
    207 }
    208 
    209 int
    210 compmove()
    211 {
    212 	static int lmove;
    213 
    214 	if (promode)
    215 		lmove = promove();
    216 	else {
    217 		do {
    218 			lmove = (lmove + 1) % RANKS;
    219 		} while (!comphand[lmove] || comphand[lmove] == CARDS);
    220 	}
    221 	asked[lmove] = 1;
    222 
    223 	(void)printf("I ask you for: %s.\n", cards[lmove]);
    224 	return(lmove);
    225 }
    226 
    227 int
    228 promove()
    229 {
    230 	int i, max;
    231 
    232 	for (i = 0; i < RANKS; ++i)
    233 		if (userasked[i] &&
    234 		    comphand[i] > 0 && comphand[i] < CARDS) {
    235 			userasked[i] = 0;
    236 			return(i);
    237 		}
    238 	if (nrandom(3) == 1) {
    239 		for (i = 0;; ++i)
    240 			if (comphand[i] && comphand[i] != CARDS) {
    241 				max = i;
    242 				break;
    243 			}
    244 		while (++i < RANKS)
    245 			if (comphand[i] != CARDS &&
    246 			    comphand[i] > comphand[max])
    247 				max = i;
    248 		return(max);
    249 	}
    250 	if (nrandom(1024) == 0723) {
    251 		for (i = 0; i < RANKS; ++i)
    252 			if (userhand[i] && comphand[i])
    253 				return(i);
    254 	}
    255 	for (;;) {
    256 		for (i = 0; i < RANKS; ++i)
    257 			if (comphand[i] && comphand[i] != CARDS &&
    258 			    !asked[i])
    259 				return(i);
    260 		for (i = 0; i < RANKS; ++i)
    261 			asked[i] = 0;
    262 	}
    263 	/* NOTREACHED */
    264 }
    265 
    266 int
    267 drawcard(player, hand)
    268 	int player;
    269 	int *hand;
    270 {
    271 	int card;
    272 
    273 	while (deck[card = nrandom(RANKS)] == 0);
    274 	++hand[card];
    275 	--deck[card];
    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 	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 	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 	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 	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, rank;
    427 
    428 	for (i = 0; i < RANKS; ++i)
    429 		deck[i] = CARDS;
    430 	for (i = 0; i < HANDSIZE; ++i) {
    431 		while (!deck[rank = nrandom(RANKS)]);
    432 		++userhand[rank];
    433 		--deck[rank];
    434 	}
    435 	for (i = 0; i < HANDSIZE; ++i) {
    436 		while (!deck[rank = nrandom(RANKS)]);
    437 		++comphand[rank];
    438 		--deck[rank];
    439 	}
    440 }
    441 
    442 int
    443 nrandom(n)
    444 	int n;
    445 {
    446 
    447 	return((int)random() % n);
    448 }
    449 
    450 void
    451 instructions()
    452 {
    453 	int input;
    454 	pid_t pid;
    455 	int fd;
    456 	const char *pager;
    457 	int status;
    458 
    459 	(void)printf("Would you like instructions (y or n)? ");
    460 	input = getchar();
    461 	while (getchar() != '\n');
    462 	if (input != 'y')
    463 		return;
    464 
    465 	switch (pid = fork()) {
    466 	case 0: /* child */
    467 		if (!isatty(1))
    468 			pager = "cat";
    469 		else {
    470 			if (!(pager = getenv("PAGER")) || (*pager == 0))
    471 				pager = _PATH_MORE;
    472 		}
    473 		if ((fd = open(_PATH_INSTR, O_RDONLY)) == -1)
    474 			err(1, "open %s", _PATH_INSTR);
    475 		if (dup2(fd, 0) == -1)
    476 			err(1, "dup2");
    477 		(void)execl("/bin/sh", "sh", "-c", pager, NULL);
    478 		err(1, "exec sh -c %s", pager);
    479 		/*NOTREACHED*/
    480 	case -1:
    481 		err(1, "fork");
    482 		/*NOTREACHED*/
    483 	default:
    484 		(void)waitpid(pid, &status, 0);
    485 		break;
    486 	}
    487 	(void)printf("Hit return to continue...\n");
    488 	while ((input = getchar()) != EOF && input != '\n');
    489 }
    490 
    491 void
    492 usage()
    493 {
    494 	(void)fprintf(stderr, "usage: fish [-p]\n");
    495 	exit(1);
    496 }
    497