fish.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495
  1. /* $NetBSD: fish.c,v 1.16 2005/02/15 12:56:20 jsm Exp $ */
  2. /*-
  3. * Copyright (c) 1990, 1993
  4. * The Regents of the University of California. All rights reserved.
  5. *
  6. * This code is derived from software contributed to Berkeley by
  7. * Muffy Barkocy.
  8. *
  9. * Redistribution and use in source and binary forms, with or without
  10. * modification, are permitted provided that the following conditions
  11. * are met:
  12. * 1. Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. * 2. Redistributions in binary form must reproduce the above copyright
  15. * notice, this list of conditions and the following disclaimer in the
  16. * documentation and/or other materials provided with the distribution.
  17. * 3. Neither the name of the University nor the names of its contributors
  18. * may be used to endorse or promote products derived from this software
  19. * without specific prior written permission.
  20. *
  21. * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24. * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31. * SUCH DAMAGE.
  32. */
  33. #include <sys/cdefs.h>
  34. #ifndef lint
  35. __COPYRIGHT("@(#) Copyright (c) 1990, 1993\n\
  36. The Regents of the University of California. All rights reserved.\n");
  37. #endif /* not lint */
  38. #ifndef lint
  39. #if 0
  40. static char sccsid[] = "@(#)fish.c 8.1 (Berkeley) 5/31/93";
  41. #else
  42. __RCSID("$NetBSD: fish.c,v 1.16 2005/02/15 12:56:20 jsm Exp $");
  43. #endif
  44. #endif /* not lint */
  45. #include <sys/types.h>
  46. #include <sys/wait.h>
  47. #include <errno.h>
  48. #include <fcntl.h>
  49. #include <stdio.h>
  50. #include <stdlib.h>
  51. #include <unistd.h>
  52. #include <string.h>
  53. #include <time.h>
  54. #include <err.h>
  55. #include "pathnames.h"
  56. #define RANKS 13
  57. #define HANDSIZE 7
  58. #define CARDS 4
  59. #define TOTCARDS RANKS * CARDS
  60. #define USER 1
  61. #define COMPUTER 0
  62. #define OTHER(a) (1 - (a))
  63. const char *const cards[] = {
  64. "A", "2", "3", "4", "5", "6", "7",
  65. "8", "9", "10", "J", "Q", "K", NULL,
  66. };
  67. #define PRC(card) (void)printf(" %s", cards[card])
  68. int promode;
  69. int asked[RANKS], comphand[RANKS], deck[TOTCARDS];
  70. int userasked[RANKS], userhand[RANKS];
  71. int curcard = TOTCARDS;
  72. void chkwinner(int, const int *);
  73. int compmove(void);
  74. int countbooks(const int *);
  75. int countcards(const int *);
  76. int drawcard(int, int *);
  77. int gofish(int, int, int *);
  78. void goodmove(int, int, int *, int *);
  79. void init(void);
  80. void instructions(void);
  81. int main(int, char *[]);
  82. int nrandom(int);
  83. void printhand(const int *);
  84. void printplayer(int);
  85. int promove(void);
  86. void usage(void) __attribute__((__noreturn__));
  87. int usermove(void);
  88. int
  89. main(argc, argv)
  90. int argc;
  91. char **argv;
  92. {
  93. int ch, move;
  94. /* Revoke setgid privileges */
  95. setregid(getgid(), getgid());
  96. while ((ch = getopt(argc, argv, "p")) != -1)
  97. switch(ch) {
  98. case 'p':
  99. promode = 1;
  100. break;
  101. case '?':
  102. default:
  103. usage();
  104. }
  105. srandom(time((time_t *)NULL));
  106. instructions();
  107. init();
  108. if (nrandom(2) == 1) {
  109. printplayer(COMPUTER);
  110. (void)printf("get to start.\n");
  111. goto istart;
  112. }
  113. printplayer(USER);
  114. (void)printf("get to start.\n");
  115. for (;;) {
  116. move = usermove();
  117. if (!comphand[move]) {
  118. if (gofish(move, USER, userhand))
  119. continue;
  120. } else {
  121. goodmove(USER, move, userhand, comphand);
  122. continue;
  123. }
  124. istart: for (;;) {
  125. move = compmove();
  126. if (!userhand[move]) {
  127. if (!gofish(move, COMPUTER, comphand))
  128. break;
  129. } else
  130. goodmove(COMPUTER, move, comphand, userhand);
  131. }
  132. }
  133. /* NOTREACHED */
  134. }
  135. int
  136. usermove()
  137. {
  138. int n;
  139. const char *const *p;
  140. char buf[256];
  141. (void)printf("\nYour hand is:");
  142. printhand(userhand);
  143. for (;;) {
  144. (void)printf("You ask me for: ");
  145. (void)fflush(stdout);
  146. if (fgets(buf, sizeof(buf), stdin) == NULL)
  147. exit(0);
  148. if (buf[0] == '\0')
  149. continue;
  150. if (buf[0] == '\n') {
  151. (void)printf("%d cards in my hand, %d in the pool.\n",
  152. countcards(comphand), curcard);
  153. (void)printf("My books:");
  154. (void)countbooks(comphand);
  155. continue;
  156. }
  157. buf[strlen(buf) - 1] = '\0';
  158. if (!strcasecmp(buf, "p") && !promode) {
  159. promode = 1;
  160. (void)printf("Entering pro mode.\n");
  161. continue;
  162. }
  163. if (!strcasecmp(buf, "quit"))
  164. exit(0);
  165. for (p = cards; *p; ++p)
  166. if (!strcasecmp(*p, buf))
  167. break;
  168. if (!*p) {
  169. (void)printf("I don't understand!\n");
  170. continue;
  171. }
  172. n = p - cards;
  173. if (userhand[n]) {
  174. userasked[n] = 1;
  175. return(n);
  176. }
  177. if (nrandom(3) == 1)
  178. (void)printf("You don't have any of those!\n");
  179. else
  180. (void)printf("You don't have any %s's!\n", cards[n]);
  181. if (nrandom(4) == 1)
  182. (void)printf("No cheating!\n");
  183. (void)printf("Guess again.\n");
  184. }
  185. /* NOTREACHED */
  186. }
  187. int
  188. compmove()
  189. {
  190. static int lmove;
  191. if (promode)
  192. lmove = promove();
  193. else {
  194. do {
  195. lmove = (lmove + 1) % RANKS;
  196. } while (!comphand[lmove] || comphand[lmove] == CARDS);
  197. }
  198. asked[lmove] = 1;
  199. (void)printf("I ask you for: %s.\n", cards[lmove]);
  200. return(lmove);
  201. }
  202. int
  203. promove()
  204. {
  205. int i, max;
  206. for (i = 0; i < RANKS; ++i)
  207. if (userasked[i] &&
  208. comphand[i] > 0 && comphand[i] < CARDS) {
  209. userasked[i] = 0;
  210. return(i);
  211. }
  212. if (nrandom(3) == 1) {
  213. for (i = 0;; ++i)
  214. if (comphand[i] && comphand[i] != CARDS) {
  215. max = i;
  216. break;
  217. }
  218. while (++i < RANKS)
  219. if (comphand[i] != CARDS &&
  220. comphand[i] > comphand[max])
  221. max = i;
  222. return(max);
  223. }
  224. if (nrandom(1024) == 0723) {
  225. for (i = 0; i < RANKS; ++i)
  226. if (userhand[i] && comphand[i])
  227. return(i);
  228. }
  229. for (;;) {
  230. for (i = 0; i < RANKS; ++i)
  231. if (comphand[i] && comphand[i] != CARDS &&
  232. !asked[i])
  233. return(i);
  234. for (i = 0; i < RANKS; ++i)
  235. asked[i] = 0;
  236. }
  237. /* NOTREACHED */
  238. }
  239. int
  240. drawcard(player, hand)
  241. int player;
  242. int *hand;
  243. {
  244. int card;
  245. ++hand[card = deck[--curcard]];
  246. if (player == USER || hand[card] == CARDS) {
  247. printplayer(player);
  248. (void)printf("drew %s", cards[card]);
  249. if (hand[card] == CARDS) {
  250. (void)printf(" and made a book of %s's!\n",
  251. cards[card]);
  252. chkwinner(player, hand);
  253. } else
  254. (void)printf(".\n");
  255. }
  256. return(card);
  257. }
  258. int
  259. gofish(askedfor, player, hand)
  260. int askedfor, player;
  261. int *hand;
  262. {
  263. printplayer(OTHER(player));
  264. (void)printf("say \"GO FISH!\"\n");
  265. if (askedfor == drawcard(player, hand)) {
  266. printplayer(player);
  267. (void)printf("drew the guess!\n");
  268. printplayer(player);
  269. (void)printf("get to ask again!\n");
  270. return(1);
  271. }
  272. return(0);
  273. }
  274. void
  275. goodmove(player, move, hand, opphand)
  276. int player, move;
  277. int *hand, *opphand;
  278. {
  279. printplayer(OTHER(player));
  280. (void)printf("have %d %s%s.\n",
  281. opphand[move], cards[move], opphand[move] == 1 ? "": "'s");
  282. hand[move] += opphand[move];
  283. opphand[move] = 0;
  284. if (hand[move] == CARDS) {
  285. printplayer(player);
  286. (void)printf("made a book of %s's!\n", cards[move]);
  287. chkwinner(player, hand);
  288. }
  289. chkwinner(OTHER(player), opphand);
  290. printplayer(player);
  291. (void)printf("get another guess!\n");
  292. }
  293. void
  294. chkwinner(player, hand)
  295. int player;
  296. const int *hand;
  297. {
  298. int cb, i, ub;
  299. for (i = 0; i < RANKS; ++i)
  300. if (hand[i] > 0 && hand[i] < CARDS)
  301. return;
  302. printplayer(player);
  303. (void)printf("don't have any more cards!\n");
  304. (void)printf("My books:");
  305. cb = countbooks(comphand);
  306. (void)printf("Your books:");
  307. ub = countbooks(userhand);
  308. (void)printf("\nI have %d, you have %d.\n", cb, ub);
  309. if (ub > cb) {
  310. (void)printf("\nYou win!!!\n");
  311. if (nrandom(1024) == 0723)
  312. (void)printf("Cheater, cheater, pumpkin eater!\n");
  313. } else if (cb > ub) {
  314. (void)printf("\nI win!!!\n");
  315. if (nrandom(1024) == 0723)
  316. (void)printf("Hah! Stupid peasant!\n");
  317. } else
  318. (void)printf("\nTie!\n");
  319. exit(0);
  320. }
  321. void
  322. printplayer(player)
  323. int player;
  324. {
  325. switch (player) {
  326. case COMPUTER:
  327. (void)printf("I ");
  328. break;
  329. case USER:
  330. (void)printf("You ");
  331. break;
  332. }
  333. }
  334. void
  335. printhand(hand)
  336. const int *hand;
  337. {
  338. int book, i, j;
  339. for (book = i = 0; i < RANKS; i++)
  340. if (hand[i] < CARDS)
  341. for (j = hand[i]; --j >= 0;)
  342. PRC(i);
  343. else
  344. ++book;
  345. if (book) {
  346. (void)printf(" + Book%s of", book > 1 ? "s" : "");
  347. for (i = 0; i < RANKS; i++)
  348. if (hand[i] == CARDS)
  349. PRC(i);
  350. }
  351. (void)putchar('\n');
  352. }
  353. int
  354. countcards(hand)
  355. const int *hand;
  356. {
  357. int i, count;
  358. for (count = i = 0; i < RANKS; i++)
  359. count += *hand++;
  360. return(count);
  361. }
  362. int
  363. countbooks(hand)
  364. const int *hand;
  365. {
  366. int i, count;
  367. for (count = i = 0; i < RANKS; i++)
  368. if (hand[i] == CARDS) {
  369. ++count;
  370. PRC(i);
  371. }
  372. if (!count)
  373. (void)printf(" none");
  374. (void)putchar('\n');
  375. return(count);
  376. }
  377. void
  378. init()
  379. {
  380. int i, j, temp;
  381. for (i = 0; i < TOTCARDS; ++i)
  382. deck[i] = i % RANKS;
  383. for (i = 0; i < TOTCARDS - 1; ++i) {
  384. j = nrandom(TOTCARDS-i);
  385. if (j == 0)
  386. continue;
  387. temp = deck[i];
  388. deck[i] = deck[i+j];
  389. deck[i+j] = temp;
  390. }
  391. for (i = 0; i < HANDSIZE; ++i) {
  392. ++userhand[deck[--curcard]];
  393. ++comphand[deck[--curcard]];
  394. }
  395. }
  396. int
  397. nrandom(n)
  398. int n;
  399. {
  400. return((int)random() % n);
  401. }
  402. void
  403. instructions()
  404. {
  405. int input;
  406. pid_t pid;
  407. int fd;
  408. const char *pager;
  409. int status;
  410. (void)printf("Would you like instructions (y or n)? ");
  411. input = getchar();
  412. while (getchar() != '\n');
  413. if (input != 'y')
  414. return;
  415. switch (pid = fork()) {
  416. case 0: /* child */
  417. if (!isatty(1))
  418. pager = "cat";
  419. else {
  420. if (!(pager = getenv("PAGER")) || (*pager == 0))
  421. pager = _PATH_MORE;
  422. }
  423. if ((fd = open(_PATH_INSTR, O_RDONLY)) == -1)
  424. err(1, "open %s", _PATH_INSTR);
  425. if (dup2(fd, 0) == -1)
  426. err(1, "dup2");
  427. (void)execl("/bin/sh", "sh", "-c", pager, (char *) NULL);
  428. err(1, "exec sh -c %s", pager);
  429. /*NOTREACHED*/
  430. case -1:
  431. err(1, "fork");
  432. /*NOTREACHED*/
  433. default:
  434. (void)waitpid(pid, &status, 0);
  435. break;
  436. }
  437. (void)printf("Hit return to continue...\n");
  438. while ((input = getchar()) != EOF && input != '\n');
  439. }
  440. void
  441. usage()
  442. {
  443. (void)fprintf(stderr, "usage: fish [-p]\n");
  444. exit(1);
  445. }