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 } 439