xref: /netbsd-src/games/fish/fish.c (revision edfa83365254b6d7c6cdaa0d30b214319daeee7f)
1 /*-
2  * Copyright (c) 1990 The Regents of the University of California.
3  * 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 
37 #ifndef lint
38 char copyright[] =
39 "@(#) Copyright (c) 1990 The Regents of the University of California.\n\
40  All rights reserved.\n";
41 #endif /* not lint */
42 
43 #ifndef lint
44 /*static char sccsid[] = "from: @(#)fish.c	5.4 (Berkeley) 1/18/91";*/
45 static char rcsid[] = "$Id: fish.c,v 1.2 1993/08/01 18:54:54 mycroft Exp $";
46 #endif /* not lint */
47 
48 #include <sys/types.h>
49 #include <sys/errno.h>
50 #include <fcntl.h>
51 #include <stdio.h>
52 #include <stdlib.h>
53 #include <string.h>
54 #include "pathnames.h"
55 
56 #define	RANKS		13
57 #define	HANDSIZE	7
58 #define	CARDS		4
59 
60 #define	USER		1
61 #define	COMPUTER	0
62 #define	OTHER(a)	(1 - (a))
63 
64 char *cards[] = {
65 	"A", "2", "3", "4", "5", "6", "7",
66 	"8", "9", "10", "J", "Q", "K", NULL,
67 };
68 #define	PRC(card)	(void)printf(" %s", cards[card])
69 
70 int promode;
71 int asked[RANKS], comphand[RANKS], deck[RANKS];
72 int userasked[RANKS], userhand[RANKS];
73 
74 main(argc, argv)
75 	int argc;
76 	char **argv;
77 {
78 	int ch, move;
79 
80 	while ((ch = getopt(argc, argv, "p")) != EOF)
81 		switch(ch) {
82 		case 'p':
83 			promode = 1;
84 			break;
85 		case '?':
86 		default:
87 			(void)fprintf(stderr, "usage: fish [-p]\n");
88 			exit(1);
89 		}
90 
91 	srandom(time((time_t *)NULL));
92 	instructions();
93 	init();
94 
95 	if (nrandom(2) == 1) {
96 		printplayer(COMPUTER);
97 		(void)printf("get to start.\n");
98 		goto istart;
99 	}
100 	printplayer(USER);
101 	(void)printf("get to start.\n");
102 
103 	for (;;) {
104 		move = usermove();
105 		if (!comphand[move]) {
106 			if (gofish(move, USER, userhand))
107 				continue;
108 		} else {
109 			goodmove(USER, move, userhand, comphand);
110 			continue;
111 		}
112 
113 istart:		for (;;) {
114 			move = compmove();
115 			if (!userhand[move]) {
116 				if (!gofish(move, COMPUTER, comphand))
117 					break;
118 			} else
119 				goodmove(COMPUTER, move, comphand, userhand);
120 		}
121 	}
122 	/* NOTREACHED */
123 }
124 
125 usermove()
126 {
127 	register int n;
128 	register char **p;
129 	char buf[256];
130 
131 	(void)printf("\nYour hand is:");
132 	printhand(userhand);
133 
134 	for (;;) {
135 		(void)printf("You ask me for: ");
136 		(void)fflush(stdout);
137 		if (fgets(buf, BUFSIZ, stdin) == NULL)
138 			exit(0);
139 		if (buf[0] == '\0')
140 			continue;
141 		if (buf[0] == '\n') {
142 			(void)printf("%d cards in my hand, %d in the pool.\n",
143 			    countcards(comphand), countcards(deck));
144 			(void)printf("My books:");
145 			(void)countbooks(comphand);
146 			continue;
147 		}
148 		buf[strlen(buf) - 1] = '\0';
149 		if (!strcasecmp(buf, "p") && !promode) {
150 			promode = 1;
151 			(void)printf("Entering pro mode.\n");
152 			continue;
153 		}
154 		if (!strcasecmp(buf, "quit"))
155 			exit(0);
156 		for (p = cards; *p; ++p)
157 			if (!strcasecmp(*p, buf))
158 				break;
159 		if (!*p) {
160 			(void)printf("I don't understand!\n");
161 			continue;
162 		}
163 		n = p - cards;
164 		if (userhand[n]) {
165 			userasked[n] = 1;
166 			return(n);
167 		}
168 		if (nrandom(3) == 1)
169 			(void)printf("You don't have any of those!\n");
170 		else
171 			(void)printf("You don't have any %s's!\n", cards[n]);
172 		if (nrandom(4) == 1)
173 			(void)printf("No cheating!\n");
174 		(void)printf("Guess again.\n");
175 	}
176 	/* NOTREACHED */
177 }
178 
179 compmove()
180 {
181 	static int lmove;
182 
183 	if (promode)
184 		lmove = promove();
185 	else {
186 		do {
187 			lmove = (lmove + 1) % RANKS;
188 		} while (!comphand[lmove] || comphand[lmove] == CARDS);
189 	}
190 	asked[lmove] = 1;
191 
192 	(void)printf("I ask you for: %s.\n", cards[lmove]);
193 	return(lmove);
194 }
195 
196 promove()
197 {
198 	register int i, max;
199 
200 	for (i = 0; i < RANKS; ++i)
201 		if (userasked[i] &&
202 		    comphand[i] > 0 && comphand[i] < CARDS) {
203 			userasked[i] = 0;
204 			return(i);
205 		}
206 	if (nrandom(3) == 1) {
207 		for (i = 0;; ++i)
208 			if (comphand[i] && comphand[i] != CARDS) {
209 				max = i;
210 				break;
211 			}
212 		while (++i < RANKS)
213 			if (comphand[i] != CARDS &&
214 			    comphand[i] > comphand[max])
215 				max = i;
216 		return(max);
217 	}
218 	if (nrandom(1024) == 0723) {
219 		for (i = 0; i < RANKS; ++i)
220 			if (userhand[i] && comphand[i])
221 				return(i);
222 	}
223 	for (;;) {
224 		for (i = 0; i < RANKS; ++i)
225 			if (comphand[i] && comphand[i] != CARDS &&
226 			    !asked[i])
227 				return(i);
228 		for (i = 0; i < RANKS; ++i)
229 			asked[i] = 0;
230 	}
231 	/* NOTREACHED */
232 }
233 
234 drawcard(player, hand)
235 	int player;
236 	int *hand;
237 {
238 	int card;
239 
240 	while (deck[card = nrandom(RANKS)] == 0);
241 	++hand[card];
242 	--deck[card];
243 	if (player == USER || hand[card] == CARDS) {
244 		printplayer(player);
245 		(void)printf("drew %s", cards[card]);
246 		if (hand[card] == CARDS) {
247 			(void)printf(" and made a book of %s's!\n",
248 			     cards[card]);
249 			chkwinner(player, hand);
250 		} else
251 			(void)printf(".\n");
252 	}
253 	return(card);
254 }
255 
256 gofish(askedfor, player, hand)
257 	int askedfor, player;
258 	int *hand;
259 {
260 	printplayer(OTHER(player));
261 	(void)printf("say \"GO FISH!\"\n");
262 	if (askedfor == drawcard(player, hand)) {
263 		printplayer(player);
264 		(void)printf("drew the guess!\n");
265 		printplayer(player);
266 		(void)printf("get to ask again!\n");
267 		return(1);
268 	}
269 	return(0);
270 }
271 
272 goodmove(player, move, hand, opphand)
273 	int player, move;
274 	int *hand, *opphand;
275 {
276 	printplayer(OTHER(player));
277 	(void)printf("have %d %s%s.\n",
278 	    opphand[move], cards[move], opphand[move] == 1 ? "": "'s");
279 
280 	hand[move] += opphand[move];
281 	opphand[move] = 0;
282 
283 	if (hand[move] == CARDS) {
284 		printplayer(player);
285 		(void)printf("made a book of %s's!\n", cards[move]);
286 		chkwinner(player, hand);
287 	}
288 
289 	chkwinner(OTHER(player), opphand);
290 
291 	printplayer(player);
292 	(void)printf("get another guess!\n");
293 }
294 
295 chkwinner(player, hand)
296 	int player;
297 	register int *hand;
298 {
299 	register int cb, i, ub;
300 
301 	for (i = 0; i < RANKS; ++i)
302 		if (hand[i] > 0 && hand[i] < CARDS)
303 			return;
304 	printplayer(player);
305 	(void)printf("don't have any more cards!\n");
306 	(void)printf("My books:");
307 	cb = countbooks(comphand);
308 	(void)printf("Your books:");
309 	ub = countbooks(userhand);
310 	(void)printf("\nI have %d, you have %d.\n", cb, ub);
311 	if (ub > cb) {
312 		(void)printf("\nYou win!!!\n");
313 		if (nrandom(1024) == 0723)
314 			(void)printf("Cheater, cheater, pumpkin eater!\n");
315 	} else if (cb > ub) {
316 		(void)printf("\nI win!!!\n");
317 		if (nrandom(1024) == 0723)
318 			(void)printf("Hah!  Stupid peasant!\n");
319 	} else
320 		(void)printf("\nTie!\n");
321 	exit(0);
322 }
323 
324 printplayer(player)
325 	int player;
326 {
327 	switch (player) {
328 	case COMPUTER:
329 		(void)printf("I ");
330 		break;
331 	case USER:
332 		(void)printf("You ");
333 		break;
334 	}
335 }
336 
337 printhand(hand)
338 	int *hand;
339 {
340 	register int book, i, j;
341 
342 	for (book = i = 0; i < RANKS; i++)
343 		if (hand[i] < CARDS)
344 			for (j = hand[i]; --j >= 0;)
345 				PRC(i);
346 		else
347 			++book;
348 	if (book) {
349 		(void)printf(" + Book%s of", book > 1 ? "s" : "");
350 		for (i = 0; i < RANKS; i++)
351 			if (hand[i] == CARDS)
352 				PRC(i);
353 	}
354 	(void)putchar('\n');
355 }
356 
357 countcards(hand)
358 	register int *hand;
359 {
360 	register int i, count;
361 
362 	for (count = i = 0; i < RANKS; i++)
363 		count += *hand++;
364 	return(count);
365 }
366 
367 countbooks(hand)
368 	int *hand;
369 {
370 	int i, count;
371 
372 	for (count = i = 0; i < RANKS; i++)
373 		if (hand[i] == CARDS) {
374 			++count;
375 			PRC(i);
376 		}
377 	if (!count)
378 		(void)printf(" none");
379 	(void)putchar('\n');
380 	return(count);
381 }
382 
383 init()
384 {
385 	register int i, rank;
386 
387 	for (i = 0; i < RANKS; ++i)
388 		deck[i] = CARDS;
389 	for (i = 0; i < HANDSIZE; ++i) {
390 		while (!deck[rank = nrandom(RANKS)]);
391 		++userhand[rank];
392 		--deck[rank];
393 	}
394 	for (i = 0; i < HANDSIZE; ++i) {
395 		while (!deck[rank = nrandom(RANKS)]);
396 		++comphand[rank];
397 		--deck[rank];
398 	}
399 }
400 
401 nrandom(n)
402 	int n;
403 {
404 	long random();
405 
406 	return((int)random() % n);
407 }
408 
409 instructions()
410 {
411 	int input;
412 	char buf[1024];
413 
414 	(void)printf("Would you like instructions (y or n)? ");
415 	input = getchar();
416 	while (getchar() != '\n');
417 	if (input != 'y')
418 		return;
419 
420 	(void)sprintf(buf, "%s %s", _PATH_MORE, _PATH_INSTR);
421 	(void)system(buf);
422 	(void)printf("Hit return to continue...\n");
423 	while ((input = getchar()) != EOF && input != '\n');
424 }
425 
426 usage()
427 {
428 	(void)fprintf(stderr, "usage: fish [-p]\n");
429 	exit(1);
430 }
431