xref: /dragonfly/games/fish/fish.c (revision 864b1bf00d7b22db663382e0b04c5dd823f0630e)
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