Home | History | Annotate | Line # | Download | only in fish
fish.c revision 1.7
      1 /*	$NetBSD: fish.c,v 1.7 1999/04/24 22:09:06 kristerw 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.7 1999/04/24 22:09:06 kristerw 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 	while ((ch = getopt(argc, argv, "p")) != -1)
    108 		switch(ch) {
    109 		case 'p':
    110 			promode = 1;
    111 			break;
    112 		case '?':
    113 		default:
    114 			(void)fprintf(stderr, "usage: fish [-p]\n");
    115 			exit(1);
    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 	char **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), countcards(deck));
    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 	while (deck[card = nrandom(RANKS)] == 0);
    272 	++hand[card];
    273 	--deck[card];
    274 	if (player == USER || hand[card] == CARDS) {
    275 		printplayer(player);
    276 		(void)printf("drew %s", cards[card]);
    277 		if (hand[card] == CARDS) {
    278 			(void)printf(" and made a book of %s's!\n",
    279 			     cards[card]);
    280 			chkwinner(player, hand);
    281 		} else
    282 			(void)printf(".\n");
    283 	}
    284 	return(card);
    285 }
    286 
    287 int
    288 gofish(askedfor, player, hand)
    289 	int askedfor, player;
    290 	int *hand;
    291 {
    292 	printplayer(OTHER(player));
    293 	(void)printf("say \"GO FISH!\"\n");
    294 	if (askedfor == drawcard(player, hand)) {
    295 		printplayer(player);
    296 		(void)printf("drew the guess!\n");
    297 		printplayer(player);
    298 		(void)printf("get to ask again!\n");
    299 		return(1);
    300 	}
    301 	return(0);
    302 }
    303 
    304 void
    305 goodmove(player, move, hand, opphand)
    306 	int player, move;
    307 	int *hand, *opphand;
    308 {
    309 	printplayer(OTHER(player));
    310 	(void)printf("have %d %s%s.\n",
    311 	    opphand[move], cards[move], opphand[move] == 1 ? "": "'s");
    312 
    313 	hand[move] += opphand[move];
    314 	opphand[move] = 0;
    315 
    316 	if (hand[move] == CARDS) {
    317 		printplayer(player);
    318 		(void)printf("made a book of %s's!\n", cards[move]);
    319 		chkwinner(player, hand);
    320 	}
    321 
    322 	chkwinner(OTHER(player), opphand);
    323 
    324 	printplayer(player);
    325 	(void)printf("get another guess!\n");
    326 }
    327 
    328 void
    329 chkwinner(player, hand)
    330 	int player;
    331 	int *hand;
    332 {
    333 	int cb, i, ub;
    334 
    335 	for (i = 0; i < RANKS; ++i)
    336 		if (hand[i] > 0 && hand[i] < CARDS)
    337 			return;
    338 	printplayer(player);
    339 	(void)printf("don't have any more cards!\n");
    340 	(void)printf("My books:");
    341 	cb = countbooks(comphand);
    342 	(void)printf("Your books:");
    343 	ub = countbooks(userhand);
    344 	(void)printf("\nI have %d, you have %d.\n", cb, ub);
    345 	if (ub > cb) {
    346 		(void)printf("\nYou win!!!\n");
    347 		if (nrandom(1024) == 0723)
    348 			(void)printf("Cheater, cheater, pumpkin eater!\n");
    349 	} else if (cb > ub) {
    350 		(void)printf("\nI win!!!\n");
    351 		if (nrandom(1024) == 0723)
    352 			(void)printf("Hah!  Stupid peasant!\n");
    353 	} else
    354 		(void)printf("\nTie!\n");
    355 	exit(0);
    356 }
    357 
    358 void
    359 printplayer(player)
    360 	int player;
    361 {
    362 	switch (player) {
    363 	case COMPUTER:
    364 		(void)printf("I ");
    365 		break;
    366 	case USER:
    367 		(void)printf("You ");
    368 		break;
    369 	}
    370 }
    371 
    372 void
    373 printhand(hand)
    374 	int *hand;
    375 {
    376 	int book, i, j;
    377 
    378 	for (book = i = 0; i < RANKS; i++)
    379 		if (hand[i] < CARDS)
    380 			for (j = hand[i]; --j >= 0;)
    381 				PRC(i);
    382 		else
    383 			++book;
    384 	if (book) {
    385 		(void)printf(" + Book%s of", book > 1 ? "s" : "");
    386 		for (i = 0; i < RANKS; i++)
    387 			if (hand[i] == CARDS)
    388 				PRC(i);
    389 	}
    390 	(void)putchar('\n');
    391 }
    392 
    393 int
    394 countcards(hand)
    395 	int *hand;
    396 {
    397 	int i, count;
    398 
    399 	for (count = i = 0; i < RANKS; i++)
    400 		count += *hand++;
    401 	return(count);
    402 }
    403 
    404 int
    405 countbooks(hand)
    406 	int *hand;
    407 {
    408 	int i, count;
    409 
    410 	for (count = i = 0; i < RANKS; i++)
    411 		if (hand[i] == CARDS) {
    412 			++count;
    413 			PRC(i);
    414 		}
    415 	if (!count)
    416 		(void)printf(" none");
    417 	(void)putchar('\n');
    418 	return(count);
    419 }
    420 
    421 void
    422 init()
    423 {
    424 	int i, rank;
    425 
    426 	for (i = 0; i < RANKS; ++i)
    427 		deck[i] = CARDS;
    428 	for (i = 0; i < HANDSIZE; ++i) {
    429 		while (!deck[rank = nrandom(RANKS)]);
    430 		++userhand[rank];
    431 		--deck[rank];
    432 	}
    433 	for (i = 0; i < HANDSIZE; ++i) {
    434 		while (!deck[rank = nrandom(RANKS)]);
    435 		++comphand[rank];
    436 		--deck[rank];
    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 status;
    454 
    455 	(void)printf("Would you like instructions (y or n)? ");
    456 	input = getchar();
    457 	while (getchar() != '\n');
    458 	if (input != 'y')
    459 		return;
    460 
    461 	switch (pid = fork()) {
    462 	case 0: /* child */
    463 		(void)setuid(getuid());
    464 		(void)setgid(getgid());
    465 		(void)execl(_PATH_MORE, "more", _PATH_INSTR, NULL);
    466 		err(1, "%s %s", _PATH_MORE, _PATH_INSTR);
    467 		/*NOTREACHED*/
    468 	case -1:
    469 		err(1, "fork");
    470 		/*NOTREACHED*/
    471 	default:
    472 		(void)waitpid(pid, &status, 0);
    473 		break;
    474 	}
    475 	(void)printf("Hit return to continue...\n");
    476 	while ((input = getchar()) != EOF && input != '\n');
    477 }
    478 
    479 void
    480 usage()
    481 {
    482 	(void)fprintf(stderr, "usage: fish [-p]\n");
    483 	exit(1);
    484 }
    485