xref: /dragonfly/games/fish/fish.c (revision 678e8cc6)
1 /*-
2  * Copyright (c) 1990, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Muffy Barkocy.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  * $FreeBSD: src/games/fish/fish.c,v 1.9 1999/12/10 16:21:50 billf Exp $
33  * $DragonFly: src/games/fish/fish.c,v 1.4 2005/07/31 20:40:26 swildner Exp $
34  *
35  * @(#) Copyright (c) 1990, 1993 The Regents of the University of California.  All rights reserved.
36  * @(#)fish.c	8.1 (Berkeley) 5/31/93
37  */
38 
39 #include <sys/types.h>
40 #include <errno.h>
41 #include <fcntl.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <unistd.h>
46 #include "pathnames.h"
47 
48 #define	RANKS		13
49 #define	HANDSIZE	7
50 #define	CARDS		4
51 
52 #define	USER		1
53 #define	COMPUTER	0
54 #define	OTHER(a)	(1 - (a))
55 
56 const char *cards[] = {
57 	"A", "2", "3", "4", "5", "6", "7",
58 	"8", "9", "10", "J", "Q", "K", NULL,
59 };
60 #define	PRC(card)	printf(" %s", cards[card])
61 
62 int promode;
63 int asked[RANKS], comphand[RANKS], deck[RANKS];
64 int userasked[RANKS], userhand[RANKS];
65 
66 static void chkwinner(int, int *);
67 static int compmove(void);
68 static int countbooks(int *);
69 static int countcards(int *);
70 static int drawcard(int, int *);
71 static int gofish(int, int, int *);
72 static void goodmove(int, int, int *, int *);
73 static void init(void);
74 static void instructions(void);
75 static int nrandom(int);
76 static void printhand(int *);
77 static void printplayer(int);
78 static int promove(void);
79 static void usage(void);
80 static int usermove(void);
81 
82 int
83 main(int argc, char **argv)
84 {
85 	int ch, move;
86 
87 	while ((ch = getopt(argc, argv, "p")) != -1)
88 		switch(ch) {
89 		case 'p':
90 			promode = 1;
91 			break;
92 		case '?':
93 		default:
94 			usage();
95 		}
96 
97 	srandomdev();
98 	instructions();
99 	init();
100 
101 	if (nrandom(2) == 1) {
102 		printplayer(COMPUTER);
103 		printf("get to start.\n");
104 		goto istart;
105 	}
106 	printplayer(USER);
107 	printf("get to start.\n");
108 
109 	for (;;) {
110 		move = usermove();
111 		if (!comphand[move]) {
112 			if (gofish(move, USER, userhand))
113 				continue;
114 		} else {
115 			goodmove(USER, move, userhand, comphand);
116 			continue;
117 		}
118 
119 istart:		for (;;) {
120 			move = compmove();
121 			if (!userhand[move]) {
122 				if (!gofish(move, COMPUTER, comphand))
123 					break;
124 			} else
125 				goodmove(COMPUTER, move, comphand, userhand);
126 		}
127 	}
128 	/* NOTREACHED */
129 	return (EXIT_FAILURE);
130 }
131 
132 static int
133 usermove(void)
134 {
135 	int n;
136 	const char **p;
137 	char buf[256];
138 
139 	printf("\nYour hand is:");
140 	printhand(userhand);
141 
142 	for (;;) {
143 		printf("You ask me for: ");
144 		fflush(stdout);
145 		if (fgets(buf, sizeof(buf), stdin) == NULL)
146 			exit(0);
147 		if (buf[0] == '\0')
148 			continue;
149 		if (buf[0] == '\n') {
150 			printf("%d cards in my hand, %d in the pool.\n",
151 			    countcards(comphand), countcards(deck));
152 			printf("My books:");
153 			countbooks(comphand);
154 			continue;
155 		}
156 		buf[strlen(buf) - 1] = '\0';
157 		if (!strcasecmp(buf, "p") && !promode) {
158 			promode = 1;
159 			printf("Entering pro mode.\n");
160 			continue;
161 		}
162 		if (!strcasecmp(buf, "quit"))
163 			exit(0);
164 		for (p = cards; *p; ++p)
165 			if (!strcasecmp(*p, buf))
166 				break;
167 		if (!*p) {
168 			printf("I don't understand!\n");
169 			continue;
170 		}
171 		n = p - cards;
172 		if (userhand[n]) {
173 			userasked[n] = 1;
174 			return(n);
175 		}
176 		if (nrandom(3) == 1)
177 			printf("You don't have any of those!\n");
178 		else
179 			printf("You don't have any %s's!\n", cards[n]);
180 		if (nrandom(4) == 1)
181 			printf("No cheating!\n");
182 		printf("Guess again.\n");
183 	}
184 	/* NOTREACHED */
185 }
186 
187 static int
188 compmove(void)
189 {
190 	static int lmove;
191 
192 	if (promode)
193 		lmove = promove();
194 	else {
195 		do {
196 			lmove = (lmove + 1) % RANKS;
197 		} while (!comphand[lmove] || comphand[lmove] == CARDS);
198 	}
199 	asked[lmove] = 1;
200 
201 	printf("I ask you for: %s.\n", cards[lmove]);
202 	return(lmove);
203 }
204 
205 static int
206 promove(void)
207 {
208 	int i, max;
209 
210 	for (i = 0; i < RANKS; ++i)
211 		if (userasked[i] && comphand[i] > 0 && comphand[i] < CARDS) {
212 			userasked[i] = 0;
213 			return(i);
214 		}
215 	if (nrandom(3) == 1) {
216 		for (i = 0;; ++i)
217 			if (comphand[i] && comphand[i] != CARDS) {
218 				max = i;
219 				break;
220 			}
221 		while (++i < RANKS)
222 			if (comphand[i] != CARDS && comphand[i] > comphand[max])
223 				max = i;
224 		return(max);
225 	}
226 	if (nrandom(1024) == 0723) {
227 		for (i = 0; i < RANKS; ++i)
228 			if (userhand[i] && comphand[i])
229 				return(i);
230 	}
231 	for (;;) {
232 		for (i = 0; i < RANKS; ++i)
233 			if (comphand[i] && comphand[i] != CARDS && !asked[i])
234 				return(i);
235 		for (i = 0; i < RANKS; ++i)
236 			asked[i] = 0;
237 	}
238 	/* NOTREACHED */
239 }
240 
241 static int
242 drawcard(int player, int *hand)
243 {
244 	int card;
245 
246 	while (deck[card = nrandom(RANKS)] == 0)
247 		; /* nothing */
248 	++hand[card];
249 	--deck[card];
250 	if (player == USER || hand[card] == CARDS) {
251 		printplayer(player);
252 		printf("drew %s", cards[card]);
253 		if (hand[card] == CARDS) {
254 			printf(" and made a book of %s's!\n", cards[card]);
255 			chkwinner(player, hand);
256 		} else
257 			printf(".\n");
258 	}
259 	return(card);
260 }
261 
262 static int
263 gofish(int askedfor, int player, int *hand)
264 {
265 	printplayer(OTHER(player));
266 	printf("say \"GO FISH!\"\n");
267 	if (askedfor == drawcard(player, hand)) {
268 		printplayer(player);
269 		printf("drew the guess!\n");
270 		printplayer(player);
271 		printf("get to ask again!\n");
272 		return(1);
273 	}
274 	return(0);
275 }
276 
277 static void
278 goodmove(int player, int move, int *hand, int *opphand)
279 {
280 	printplayer(OTHER(player));
281 	printf("have %d %s%s.\n",
282 	    opphand[move], cards[move], opphand[move] == 1 ? "": "'s");
283 
284 	hand[move] += opphand[move];
285 	opphand[move] = 0;
286 
287 	if (hand[move] == CARDS) {
288 		printplayer(player);
289 		printf("made a book of %s's!\n", cards[move]);
290 		chkwinner(player, hand);
291 	}
292 
293 	chkwinner(OTHER(player), opphand);
294 
295 	printplayer(player);
296 	printf("get another guess!\n");
297 }
298 
299 static void
300 chkwinner(int player, int *hand)
301 {
302 	int cb, i, ub;
303 
304 	for (i = 0; i < RANKS; ++i)
305 		if (hand[i] > 0 && hand[i] < CARDS)
306 			return;
307 	printplayer(player);
308 	printf("don't have any more cards!\n");
309 	printf("My books:");
310 	cb = countbooks(comphand);
311 	printf("Your books:");
312 	ub = countbooks(userhand);
313 	printf("\nI have %d, you have %d.\n", cb, ub);
314 	if (ub > cb) {
315 		printf("\nYou win!!!\n");
316 		if (nrandom(1024) == 0723)
317 			printf("Cheater, cheater, pumpkin eater!\n");
318 	} else if (cb > ub) {
319 		printf("\nI win!!!\n");
320 		if (nrandom(1024) == 0723)
321 			printf("Hah!  Stupid peasant!\n");
322 	} else
323 		printf("\nTie!\n");
324 	exit(0);
325 }
326 
327 static void
328 printplayer(int player)
329 {
330 	switch (player) {
331 	case COMPUTER:
332 		printf("I ");
333 		break;
334 	case USER:
335 		printf("You ");
336 		break;
337 	}
338 }
339 
340 static void
341 printhand(int *hand)
342 {
343 	int book, i, j;
344 
345 	for (book = i = 0; i < RANKS; i++)
346 		if (hand[i] < CARDS)
347 			for (j = hand[i]; --j >= 0;)
348 				PRC(i);
349 		else
350 			++book;
351 	if (book) {
352 		printf(" + Book%s of", book > 1 ? "s" : "");
353 		for (i = 0; i < RANKS; i++)
354 			if (hand[i] == CARDS)
355 				PRC(i);
356 	}
357 	putchar('\n');
358 }
359 
360 static int
361 countcards(int *hand)
362 {
363 	int i, count;
364 
365 	for (count = i = 0; i < RANKS; i++)
366 		count += *hand++;
367 	return(count);
368 }
369 
370 static int
371 countbooks(int *hand)
372 {
373 	int i, count;
374 
375 	for (count = i = 0; i < RANKS; i++)
376 		if (hand[i] == CARDS) {
377 			++count;
378 			PRC(i);
379 		}
380 	if (!count)
381 		printf(" none");
382 	putchar('\n');
383 	return(count);
384 }
385 
386 static void
387 init(void)
388 {
389 	int i, rank;
390 
391 	for (i = 0; i < RANKS; ++i)
392 		deck[i] = CARDS;
393 	for (i = 0; i < HANDSIZE; ++i) {
394 		while (!deck[rank = nrandom(RANKS)])
395 			; /* nothing */
396 		++userhand[rank];
397 		--deck[rank];
398 	}
399 	for (i = 0; i < HANDSIZE; ++i) {
400 		while (!deck[rank = nrandom(RANKS)])
401 			; /* nothing */
402 		++comphand[rank];
403 		--deck[rank];
404 	}
405 }
406 
407 static int
408 nrandom(int n)
409 {
410 
411 	return((int)random() % n);
412 }
413 
414 static void
415 instructions(void)
416 {
417 	int input;
418 	char buf[1024];
419 
420 	printf("Would you like instructions (y or n)? ");
421 	input = getchar();
422 	while (getchar() != '\n');
423 	if (input != 'y')
424 		return;
425 
426 	sprintf(buf, "%s %s", _PATH_MORE, _PATH_INSTR);
427 	system(buf);
428 	printf("Hit return to continue...\n");
429 	while ((input = getchar()) != EOF && input != '\n');
430 }
431 
432 static void
433 usage(void)
434 {
435 	fprintf(stderr, "usage: fish [-p]\n");
436 	exit(1);
437 }
438