xref: /dragonfly/games/fish/fish.c (revision 984263bc)
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. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *	This product includes software developed by the University of
19  *	California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  *
36  * $FreeBSD: src/games/fish/fish.c,v 1.9 1999/12/10 16:21:50 billf Exp $
37  */
38 
39 #ifndef lint
40 static const char copyright[] =
41 "@(#) 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 #endif
49 static const char rcsid[] =
50  "$FreeBSD: src/games/fish/fish.c,v 1.9 1999/12/10 16:21:50 billf Exp $";
51 #endif /* not lint */
52 
53 #include <sys/types.h>
54 #include <sys/errno.h>
55 #include <fcntl.h>
56 #include <stdio.h>
57 #include <stdlib.h>
58 #include <string.h>
59 #include <unistd.h>
60 #include "pathnames.h"
61 
62 #define	RANKS		13
63 #define	HANDSIZE	7
64 #define	CARDS		4
65 
66 #define	USER		1
67 #define	COMPUTER	0
68 #define	OTHER(a)	(1 - (a))
69 
70 char *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 int promode;
77 int asked[RANKS], comphand[RANKS], deck[RANKS];
78 int userasked[RANKS], userhand[RANKS];
79 
80 void	chkwinner __P((int player, int *hand));
81 int	compmove __P((void));
82 int	countbooks __P((int *hand));
83 int	countcards __P((int *hand));
84 int	drawcard __P((int player, int *hand));
85 int	gofish __P((int askedfor, int player, int *hand));
86 void	goodmove __P((int player, int move, int *hand, int *opphand));
87 void	init __P((void));
88 void 	instructions __P((void));
89 int	nrandom __P((int n));
90 void	printhand __P((int *hand));
91 void	printplayer __P((int player));
92 int	promove __P((void));
93 void	usage __P((void));
94 int 	usermove __P((void));
95 
96 int
97 main(argc, argv)
98 	int argc;
99 	char **argv;
100 {
101 	int ch, move;
102 
103 	while ((ch = getopt(argc, argv, "p")) != -1)
104 		switch(ch) {
105 		case 'p':
106 			promode = 1;
107 			break;
108 		case '?':
109 		default:
110 			(void)fprintf(stderr, "usage: fish [-p]\n");
111 			exit(1);
112 		}
113 
114 	srandomdev();
115 	instructions();
116 	init();
117 
118 	if (nrandom(2) == 1) {
119 		printplayer(COMPUTER);
120 		(void)printf("get to start.\n");
121 		goto istart;
122 	}
123 	printplayer(USER);
124 	(void)printf("get to start.\n");
125 
126 	for (;;) {
127 		move = usermove();
128 		if (!comphand[move]) {
129 			if (gofish(move, USER, userhand))
130 				continue;
131 		} else {
132 			goodmove(USER, move, userhand, comphand);
133 			continue;
134 		}
135 
136 istart:		for (;;) {
137 			move = compmove();
138 			if (!userhand[move]) {
139 				if (!gofish(move, COMPUTER, comphand))
140 					break;
141 			} else
142 				goodmove(COMPUTER, move, comphand, userhand);
143 		}
144 	}
145 	/* NOTREACHED */
146 	return(EXIT_FAILURE);
147 }
148 
149 int
150 usermove()
151 {
152 	int n;
153 	char **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), countcards(deck));
169 			(void)printf("My books:");
170 			(void)countbooks(comphand);
171 			continue;
172 		}
173 		buf[strlen(buf) - 1] = '\0';
174 		if (!strcasecmp(buf, "p") && !promode) {
175 			promode = 1;
176 			(void)printf("Entering pro mode.\n");
177 			continue;
178 		}
179 		if (!strcasecmp(buf, "quit"))
180 			exit(0);
181 		for (p = cards; *p; ++p)
182 			if (!strcasecmp(*p, buf))
183 				break;
184 		if (!*p) {
185 			(void)printf("I don't understand!\n");
186 			continue;
187 		}
188 		n = p - cards;
189 		if (userhand[n]) {
190 			userasked[n] = 1;
191 			return(n);
192 		}
193 		if (nrandom(3) == 1)
194 			(void)printf("You don't have any of those!\n");
195 		else
196 			(void)printf("You don't have any %s's!\n", cards[n]);
197 		if (nrandom(4) == 1)
198 			(void)printf("No cheating!\n");
199 		(void)printf("Guess again.\n");
200 	}
201 	/* NOTREACHED */
202 }
203 
204 int
205 compmove()
206 {
207 	static int lmove;
208 
209 	if (promode)
210 		lmove = promove();
211 	else {
212 		do {
213 			lmove = (lmove + 1) % RANKS;
214 		} while (!comphand[lmove] || comphand[lmove] == CARDS);
215 	}
216 	asked[lmove] = 1;
217 
218 	(void)printf("I ask you for: %s.\n", cards[lmove]);
219 	return(lmove);
220 }
221 
222 int
223 promove()
224 {
225 	int i, max;
226 
227 	for (i = 0; i < RANKS; ++i)
228 		if (userasked[i] &&
229 		    comphand[i] > 0 && comphand[i] < CARDS) {
230 			userasked[i] = 0;
231 			return(i);
232 		}
233 	if (nrandom(3) == 1) {
234 		for (i = 0;; ++i)
235 			if (comphand[i] && comphand[i] != CARDS) {
236 				max = i;
237 				break;
238 			}
239 		while (++i < RANKS)
240 			if (comphand[i] != CARDS &&
241 			    comphand[i] > comphand[max])
242 				max = i;
243 		return(max);
244 	}
245 	if (nrandom(1024) == 0723) {
246 		for (i = 0; i < RANKS; ++i)
247 			if (userhand[i] && comphand[i])
248 				return(i);
249 	}
250 	for (;;) {
251 		for (i = 0; i < RANKS; ++i)
252 			if (comphand[i] && comphand[i] != CARDS &&
253 			    !asked[i])
254 				return(i);
255 		for (i = 0; i < RANKS; ++i)
256 			asked[i] = 0;
257 	}
258 	/* NOTREACHED */
259 }
260 
261 int
262 drawcard(player, hand)
263 	int player;
264 	int *hand;
265 {
266 	int card;
267 
268 	while (deck[card = nrandom(RANKS)] == 0);
269 	++hand[card];
270 	--deck[card];
271 	if (player == USER || hand[card] == CARDS) {
272 		printplayer(player);
273 		(void)printf("drew %s", cards[card]);
274 		if (hand[card] == CARDS) {
275 			(void)printf(" and made a book of %s's!\n",
276 			     cards[card]);
277 			chkwinner(player, hand);
278 		} else
279 			(void)printf(".\n");
280 	}
281 	return(card);
282 }
283 
284 int
285 gofish(askedfor, player, hand)
286 	int askedfor, player;
287 	int *hand;
288 {
289 	printplayer(OTHER(player));
290 	(void)printf("say \"GO FISH!\"\n");
291 	if (askedfor == drawcard(player, hand)) {
292 		printplayer(player);
293 		(void)printf("drew the guess!\n");
294 		printplayer(player);
295 		(void)printf("get to ask again!\n");
296 		return(1);
297 	}
298 	return(0);
299 }
300 
301 void
302 goodmove(player, move, hand, opphand)
303 	int player, move;
304 	int *hand, *opphand;
305 {
306 	printplayer(OTHER(player));
307 	(void)printf("have %d %s%s.\n",
308 	    opphand[move], cards[move], opphand[move] == 1 ? "": "'s");
309 
310 	hand[move] += opphand[move];
311 	opphand[move] = 0;
312 
313 	if (hand[move] == CARDS) {
314 		printplayer(player);
315 		(void)printf("made a book of %s's!\n", cards[move]);
316 		chkwinner(player, hand);
317 	}
318 
319 	chkwinner(OTHER(player), opphand);
320 
321 	printplayer(player);
322 	(void)printf("get another guess!\n");
323 }
324 
325 void
326 chkwinner(player, hand)
327 	int player;
328 	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 void
356 printplayer(player)
357 	int player;
358 {
359 	switch (player) {
360 	case COMPUTER:
361 		(void)printf("I ");
362 		break;
363 	case USER:
364 		(void)printf("You ");
365 		break;
366 	}
367 }
368 
369 void
370 printhand(hand)
371 	int *hand;
372 {
373 	int book, i, j;
374 
375 	for (book = i = 0; i < RANKS; i++)
376 		if (hand[i] < CARDS)
377 			for (j = hand[i]; --j >= 0;)
378 				PRC(i);
379 		else
380 			++book;
381 	if (book) {
382 		(void)printf(" + Book%s of", book > 1 ? "s" : "");
383 		for (i = 0; i < RANKS; i++)
384 			if (hand[i] == CARDS)
385 				PRC(i);
386 	}
387 	(void)putchar('\n');
388 }
389 
390 int
391 countcards(hand)
392 	int *hand;
393 {
394 	int i, count;
395 
396 	for (count = i = 0; i < RANKS; i++)
397 		count += *hand++;
398 	return(count);
399 }
400 
401 int
402 countbooks(hand)
403 	int *hand;
404 {
405 	int i, count;
406 
407 	for (count = i = 0; i < RANKS; i++)
408 		if (hand[i] == CARDS) {
409 			++count;
410 			PRC(i);
411 		}
412 	if (!count)
413 		(void)printf(" none");
414 	(void)putchar('\n');
415 	return(count);
416 }
417 
418 void
419 init()
420 {
421 	int i, rank;
422 
423 	for (i = 0; i < RANKS; ++i)
424 		deck[i] = CARDS;
425 	for (i = 0; i < HANDSIZE; ++i) {
426 		while (!deck[rank = nrandom(RANKS)]);
427 		++userhand[rank];
428 		--deck[rank];
429 	}
430 	for (i = 0; i < HANDSIZE; ++i) {
431 		while (!deck[rank = nrandom(RANKS)]);
432 		++comphand[rank];
433 		--deck[rank];
434 	}
435 }
436 
437 int
438 nrandom(n)
439 	int n;
440 {
441 
442 	return((int)random() % n);
443 }
444 
445 void
446 instructions()
447 {
448 	int input;
449 	char buf[1024];
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 	(void)sprintf(buf, "%s %s", _PATH_MORE, _PATH_INSTR);
458 	(void)system(buf);
459 	(void)printf("Hit return to continue...\n");
460 	while ((input = getchar()) != EOF && input != '\n');
461 }
462 
463 void
464 usage()
465 {
466 	(void)fprintf(stderr, "usage: fish [-p]\n");
467 	exit(1);
468 }
469