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