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