xref: /dragonfly/games/fish/fish.c (revision a7341d74)
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] <= 3) {
173 			userasked[n] = 1;
174 			return(n);
175 		}
176 		if (userhand[n] == 4) {
177 			printf("You already have all of those.\n");
178 			continue;
179 		}
180 
181 		if (nrandom(3) == 1)
182 			printf("You don't have any of those!\n");
183 		else
184 			printf("You don't have any %s's!\n", cards[n]);
185 		if (nrandom(4) == 1)
186 			printf("No cheating!\n");
187 		printf("Guess again.\n");
188 	}
189 	/* NOTREACHED */
190 }
191 
192 static int
193 compmove(void)
194 {
195 	static int lmove;
196 
197 	if (promode)
198 		lmove = promove();
199 	else {
200 		do {
201 			lmove = (lmove + 1) % RANKS;
202 		} while (!comphand[lmove] || comphand[lmove] == CARDS);
203 	}
204 	asked[lmove] = 1;
205 
206 	printf("I ask you for: %s.\n", cards[lmove]);
207 	return(lmove);
208 }
209 
210 static int
211 promove(void)
212 {
213 	int i, max;
214 
215 	for (i = 0; i < RANKS; ++i)
216 		if (userasked[i] && comphand[i] > 0 && comphand[i] < CARDS) {
217 			userasked[i] = 0;
218 			return(i);
219 		}
220 	if (nrandom(3) == 1) {
221 		for (i = 0;; ++i)
222 			if (comphand[i] && comphand[i] != CARDS) {
223 				max = i;
224 				break;
225 			}
226 		while (++i < RANKS)
227 			if (comphand[i] != CARDS && comphand[i] > comphand[max])
228 				max = i;
229 		return(max);
230 	}
231 	if (nrandom(1024) == 0723) {
232 		for (i = 0; i < RANKS; ++i)
233 			if (userhand[i] && comphand[i])
234 				return(i);
235 	}
236 	for (;;) {
237 		for (i = 0; i < RANKS; ++i)
238 			if (comphand[i] && comphand[i] != CARDS && !asked[i])
239 				return(i);
240 		for (i = 0; i < RANKS; ++i)
241 			asked[i] = 0;
242 	}
243 	/* NOTREACHED */
244 }
245 
246 static int
247 drawcard(int player, int *hand)
248 {
249 	int card;
250 
251 	while (deck[card = nrandom(RANKS)] == 0)
252 		; /* nothing */
253 	++hand[card];
254 	--deck[card];
255 	if (player == USER || hand[card] == CARDS) {
256 		printplayer(player);
257 		printf("drew %s", cards[card]);
258 		if (hand[card] == CARDS) {
259 			printf(" and made a book of %s's!\n", cards[card]);
260 			chkwinner(player, hand);
261 		} else
262 			printf(".\n");
263 	}
264 	return(card);
265 }
266 
267 static int
268 gofish(int askedfor, int player, int *hand)
269 {
270 	printplayer(OTHER(player));
271 	printf("say \"GO FISH!\"\n");
272 	if (askedfor == drawcard(player, hand)) {
273 		printplayer(player);
274 		printf("drew the guess!\n");
275 		printplayer(player);
276 		printf("get to ask again!\n");
277 		return(1);
278 	}
279 	return(0);
280 }
281 
282 static void
283 goodmove(int player, int move, int *hand, int *opphand)
284 {
285 	printplayer(OTHER(player));
286 	printf("have %d %s%s.\n",
287 	    opphand[move], cards[move], opphand[move] == 1 ? "": "'s");
288 
289 	hand[move] += opphand[move];
290 	opphand[move] = 0;
291 
292 	if (hand[move] == CARDS) {
293 		printplayer(player);
294 		printf("made a book of %s's!\n", cards[move]);
295 		chkwinner(player, hand);
296 	}
297 
298 	chkwinner(OTHER(player), opphand);
299 
300 	printplayer(player);
301 	printf("get another guess!\n");
302 }
303 
304 static void
305 chkwinner(int player, int *hand)
306 {
307 	int cb, i, ub;
308 
309 	for (i = 0; i < RANKS; ++i)
310 		if (hand[i] > 0 && hand[i] < CARDS)
311 			return;
312 	printplayer(player);
313 	printf("don't have any more cards!\n");
314 	printf("My books:");
315 	cb = countbooks(comphand);
316 	printf("Your books:");
317 	ub = countbooks(userhand);
318 	printf("\nI have %d, you have %d.\n", cb, ub);
319 	if (ub > cb) {
320 		printf("\nYou win!!!\n");
321 		if (nrandom(1024) == 0723)
322 			printf("Cheater, cheater, pumpkin eater!\n");
323 	} else if (cb > ub) {
324 		printf("\nI win!!!\n");
325 		if (nrandom(1024) == 0723)
326 			printf("Hah!  Stupid peasant!\n");
327 	} else
328 		printf("\nTie!\n");
329 	exit(0);
330 }
331 
332 static void
333 printplayer(int player)
334 {
335 	switch (player) {
336 	case COMPUTER:
337 		printf("I ");
338 		break;
339 	case USER:
340 		printf("You ");
341 		break;
342 	}
343 }
344 
345 static void
346 printhand(int *hand)
347 {
348 	int book, i, j;
349 
350 	for (book = i = 0; i < RANKS; i++)
351 		if (hand[i] < CARDS)
352 			for (j = hand[i]; --j >= 0;)
353 				PRC(i);
354 		else
355 			++book;
356 	if (book) {
357 		printf(" + Book%s of", book > 1 ? "s" : "");
358 		for (i = 0; i < RANKS; i++)
359 			if (hand[i] == CARDS)
360 				PRC(i);
361 	}
362 	putchar('\n');
363 }
364 
365 static int
366 countcards(int *hand)
367 {
368 	int i, count;
369 
370 	for (count = i = 0; i < RANKS; i++)
371 		count += *hand++;
372 	return(count);
373 }
374 
375 static int
376 countbooks(int *hand)
377 {
378 	int i, count;
379 
380 	for (count = i = 0; i < RANKS; i++)
381 		if (hand[i] == CARDS) {
382 			++count;
383 			PRC(i);
384 		}
385 	if (!count)
386 		printf(" none");
387 	putchar('\n');
388 	return(count);
389 }
390 
391 static void
392 init(void)
393 {
394 	int i, rank;
395 
396 	for (i = 0; i < RANKS; ++i)
397 		deck[i] = CARDS;
398 	for (i = 0; i < HANDSIZE; ++i) {
399 		while (!deck[rank = nrandom(RANKS)])
400 			; /* nothing */
401 		++userhand[rank];
402 		--deck[rank];
403 	}
404 	for (i = 0; i < HANDSIZE; ++i) {
405 		while (!deck[rank = nrandom(RANKS)])
406 			; /* nothing */
407 		++comphand[rank];
408 		--deck[rank];
409 	}
410 }
411 
412 static int
413 nrandom(int n)
414 {
415 
416 	return((int)random() % n);
417 }
418 
419 static void
420 instructions(void)
421 {
422 	int input;
423 	char buf[1024];
424 
425 	printf("Would you like instructions (y or n)? ");
426 	input = getchar();
427 	while (getchar() != '\n');
428 	if (input != 'y')
429 		return;
430 
431 	sprintf(buf, "%s %s", _PATH_MORE, _PATH_INSTR);
432 	system(buf);
433 	printf("Hit return to continue...\n");
434 	while ((input = getchar()) != EOF && input != '\n');
435 }
436 
437 static void
438 usage(void)
439 {
440 	fprintf(stderr, "usage: fish [-p]\n");
441 	exit(1);
442 }
443