Home | History | Annotate | Line # | Download | only in fish
fish.c revision 1.23
      1 /*	$NetBSD: fish.c,v 1.23 2018/03/05 04:59:54 eadler 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.23 2018/03/05 04:59:54 eadler 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")) {
    175 			if (!promode) {
    176 				promode = 1;
    177 				printf("Entering pro mode.\n");
    178 			}
    179 			else {
    180 				printf("Already in pro mode.\n");
    181 			}
    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] <= 3) {
    195 			userasked[n] = 1;
    196 			return(n);
    197 		}
    198 		if (userhand[n] == 4) {
    199 			printf("You already have all of those.\n");
    200 			continue;
    201 		}
    202 
    203 		if (nrandom(3) == 1)
    204 			(void)printf("You don't have any of those!\n");
    205 		else
    206 			(void)printf("You don't have any %s's!\n", cards[n]);
    207 		if (nrandom(4) == 1)
    208 			(void)printf("No cheating!\n");
    209 		(void)printf("Guess again.\n");
    210 	}
    211 	/* NOTREACHED */
    212 }
    213 
    214 static int
    215 compmove(void)
    216 {
    217 	static int lmove;
    218 
    219 	if (promode)
    220 		lmove = promove();
    221 	else {
    222 		do {
    223 			lmove = (lmove + 1) % RANKS;
    224 		} while (!comphand[lmove] || comphand[lmove] == CARDS);
    225 	}
    226 	asked[lmove] = 1;
    227 
    228 	(void)printf("I ask you for: %s.\n", cards[lmove]);
    229 	return(lmove);
    230 }
    231 
    232 static int
    233 promove(void)
    234 {
    235 	int i, max;
    236 
    237 	for (i = 0; i < RANKS; ++i)
    238 		if (userasked[i] &&
    239 		    comphand[i] > 0 && comphand[i] < CARDS) {
    240 			userasked[i] = 0;
    241 			return(i);
    242 		}
    243 	if (nrandom(3) == 1) {
    244 		for (i = 0;; ++i)
    245 			if (comphand[i] && comphand[i] != CARDS) {
    246 				max = i;
    247 				break;
    248 			}
    249 		while (++i < RANKS)
    250 			if (comphand[i] != CARDS &&
    251 			    comphand[i] > comphand[max])
    252 				max = i;
    253 		return(max);
    254 	}
    255 	if (nrandom(1024) == 0723) {
    256 		for (i = 0; i < RANKS; ++i)
    257 			if (userhand[i] && comphand[i])
    258 				return(i);
    259 	}
    260 	for (;;) {
    261 		for (i = 0; i < RANKS; ++i)
    262 			if (comphand[i] && comphand[i] != CARDS &&
    263 			    !asked[i])
    264 				return(i);
    265 		for (i = 0; i < RANKS; ++i)
    266 			asked[i] = 0;
    267 	}
    268 	/* NOTREACHED */
    269 }
    270 
    271 static int
    272 drawcard(int player, int *hand)
    273 {
    274 	int card;
    275 
    276 	++hand[card = deck[--curcard]];
    277 	if (player == USER || hand[card] == CARDS) {
    278 		printplayer(player);
    279 		(void)printf("drew %s", cards[card]);
    280 		if (hand[card] == CARDS) {
    281 			(void)printf(" and made a book of %s's!\n",
    282 			     cards[card]);
    283 			chkwinner(player, hand);
    284 		} else
    285 			(void)printf(".\n");
    286 	}
    287 	return(card);
    288 }
    289 
    290 static int
    291 gofish(int askedfor, int player, int *hand)
    292 {
    293 	printplayer(OTHER(player));
    294 	(void)printf("say \"GO FISH!\"\n");
    295 	if (askedfor == drawcard(player, hand)) {
    296 		printplayer(player);
    297 		(void)printf("drew the guess!\n");
    298 		printplayer(player);
    299 		(void)printf("get to ask again!\n");
    300 		return(1);
    301 	}
    302 	return(0);
    303 }
    304 
    305 static void
    306 goodmove(int player, int move, int *hand, int *opphand)
    307 {
    308 	printplayer(OTHER(player));
    309 	(void)printf("have %d %s%s.\n",
    310 	    opphand[move], cards[move], opphand[move] == 1 ? "": "'s");
    311 
    312 	hand[move] += opphand[move];
    313 	opphand[move] = 0;
    314 
    315 	if (hand[move] == CARDS) {
    316 		printplayer(player);
    317 		(void)printf("made a book of %s's!\n", cards[move]);
    318 		chkwinner(player, hand);
    319 	}
    320 
    321 	chkwinner(OTHER(player), opphand);
    322 
    323 	printplayer(player);
    324 	(void)printf("get another guess!\n");
    325 }
    326 
    327 static void
    328 chkwinner(int player, const int *hand)
    329 {
    330 	int cb, i, ub;
    331 
    332 	for (i = 0; i < RANKS; ++i)
    333 		if (hand[i] > 0 && hand[i] < CARDS)
    334 			return;
    335 	printplayer(player);
    336 	(void)printf("don't have any more cards!\n");
    337 	(void)printf("My books:");
    338 	cb = countbooks(comphand);
    339 	(void)printf("Your books:");
    340 	ub = countbooks(userhand);
    341 	(void)printf("\nI have %d, you have %d.\n", cb, ub);
    342 	if (ub > cb) {
    343 		(void)printf("\nYou win!!!\n");
    344 		if (nrandom(1024) == 0723)
    345 			(void)printf("Cheater, cheater, pumpkin eater!\n");
    346 	} else if (cb > ub) {
    347 		(void)printf("\nI win!!!\n");
    348 		if (nrandom(1024) == 0723)
    349 			(void)printf("Hah!  Stupid peasant!\n");
    350 	} else
    351 		(void)printf("\nTie!\n");
    352 	exit(0);
    353 }
    354 
    355 static void
    356 printplayer(int player)
    357 {
    358 	switch (player) {
    359 	case COMPUTER:
    360 		(void)printf("I ");
    361 		break;
    362 	case USER:
    363 		(void)printf("You ");
    364 		break;
    365 	}
    366 }
    367 
    368 static void
    369 printhand(const int *hand)
    370 {
    371 	int book, i, j;
    372 
    373 	for (book = i = 0; i < RANKS; i++)
    374 		if (hand[i] < CARDS)
    375 			for (j = hand[i]; --j >= 0;)
    376 				PRC(i);
    377 		else
    378 			++book;
    379 	if (book) {
    380 		(void)printf(" + Book%s of", book > 1 ? "s" : "");
    381 		for (i = 0; i < RANKS; i++)
    382 			if (hand[i] == CARDS)
    383 				PRC(i);
    384 	}
    385 	(void)putchar('\n');
    386 }
    387 
    388 static int
    389 countcards(const int *hand)
    390 {
    391 	int i, count;
    392 
    393 	for (count = i = 0; i < RANKS; i++)
    394 		count += *hand++;
    395 	return(count);
    396 }
    397 
    398 static int
    399 countbooks(const int *hand)
    400 {
    401 	int i, count;
    402 
    403 	for (count = i = 0; i < RANKS; i++)
    404 		if (hand[i] == CARDS) {
    405 			++count;
    406 			PRC(i);
    407 		}
    408 	if (!count)
    409 		(void)printf(" none");
    410 	(void)putchar('\n');
    411 	return(count);
    412 }
    413 
    414 static void
    415 init(void)
    416 {
    417 	int i, j, temp;
    418 
    419 	for (i = 0; i < TOTCARDS; ++i)
    420 		deck[i] = i % RANKS;
    421 	for (i = 0; i < TOTCARDS - 1; ++i) {
    422 		j = nrandom(TOTCARDS-i);
    423 		if (j == 0)
    424 			continue;
    425 		temp = deck[i];
    426 		deck[i] = deck[i+j];
    427 		deck[i+j] = temp;
    428 	}
    429 	for (i = 0; i < HANDSIZE; ++i) {
    430 		++userhand[deck[--curcard]];
    431 		++comphand[deck[--curcard]];
    432 	}
    433 }
    434 
    435 static int
    436 nrandom(int n)
    437 {
    438 
    439 	return((int)random() % n);
    440 }
    441 
    442 static void
    443 instructions(void)
    444 {
    445 	int input;
    446 	pid_t pid;
    447 	int fd;
    448 	const char *pager;
    449 	int status;
    450 
    451 	(void)printf("Would you like instructions (y or n)? ");
    452 	input = getchar();
    453 	while (getchar() != '\n');
    454 	if (input != 'y')
    455 		return;
    456 
    457 	switch (pid = fork()) {
    458 	case 0: /* child */
    459 		if (!isatty(1))
    460 			pager = "cat";
    461 		else {
    462 			if (!(pager = getenv("PAGER")) || (*pager == 0))
    463 				pager = _PATH_MORE;
    464 		}
    465 		if ((fd = open(_PATH_INSTR, O_RDONLY)) == -1)
    466 			err(1, "open %s", _PATH_INSTR);
    467 		if (dup2(fd, 0) == -1)
    468 			err(1, "dup2");
    469 		(void)execl("/bin/sh", "sh", "-c", pager, (char *) NULL);
    470 		err(1, "exec sh -c %s", pager);
    471 		/*NOTREACHED*/
    472 	case -1:
    473 		err(1, "fork");
    474 		/*NOTREACHED*/
    475 	default:
    476 		(void)waitpid(pid, &status, 0);
    477 		break;
    478 	}
    479 	(void)printf("Hit return to continue...\n");
    480 	while ((input = getchar()) != EOF && input != '\n');
    481 }
    482 
    483 static void
    484 usage(void)
    485 {
    486 	(void)fprintf(stderr, "usage: fish [-p]\n");
    487 	exit(1);
    488 }
    489