Initial import from FreeBSD RELENG_4:
[dragonfly.git] / games / fish / fish.c
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 }