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