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