386BSD 0.1 development
[unix-history] / usr / othersrc / games / cribbage / crib.c
CommitLineData
f6ce5b77
WJ
1/*
2 * Copyright (c) 1980 Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. 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
34#ifndef lint
35char copyright[] =
36"@(#) Copyright (c) 1980 Regents of the University of California.\n\
37 All rights reserved.\n";
38#endif /* not lint */
39
40#ifndef lint
41static char sccsid[] = "@(#)crib.c 5.6 (Berkeley) 2/28/91";
42#endif /* not lint */
43
44# include <sys/signal.h>
45# include <curses.h>
46# include "deck.h"
47# include "cribbage.h"
48# include "cribcur.h"
49# include "pathnames.h"
50
51main(argc, argv)
52int argc;
53char *argv[];
54{
55 extern char *optarg;
56 extern int optind;
57 register char *p;
58 int ch;
59 BOOLEAN playing;
60 char *s; /* for reading arguments */
61 FILE *f;
62 FILE *fopen();
63 char *getline(), *getlogin();
64 void rint();
65
66 while ((ch = getopt(argc, argv, "eqr")) != EOF)
67 switch(ch) {
68 case 'e':
69 explain = TRUE;
70 break;
71 case 'q':
72 quiet = TRUE;
73 break;
74 case 'r':
75 rflag = TRUE;
76 break;
77 case '?':
78 default:
79 (void) fprintf(stderr, "usage: cribbage [-eqr]\n");
80 exit(1);
81 }
82
83 initscr();
84 signal(SIGINT, rint);
85 crmode();
86 noecho();
87 Playwin = subwin(stdscr, PLAY_Y, PLAY_X, 0, 0);
88 Tablewin = subwin(stdscr, TABLE_Y, TABLE_X, 0, PLAY_X);
89 Compwin = subwin(stdscr, COMP_Y, COMP_X, 0, TABLE_X + PLAY_X);
90 Msgwin = subwin(stdscr, MSG_Y, MSG_X, Y_MSG_START, SCORE_X + 1);
91 leaveok(Playwin, TRUE);
92 leaveok(Tablewin, TRUE);
93 leaveok(Compwin, TRUE);
94 clearok(stdscr, FALSE);
95
96 if (!quiet) {
97 msg("Do you need instructions for cribbage? ");
98 if (getuchar() == 'Y') {
99 endwin();
100 clear();
101 mvcur(0, COLS - 1, LINES - 1, 0);
102 fflush(stdout);
103 instructions();
104 crmode();
105 noecho();
106 clear();
107 refresh();
108 msg("For the rules of this program, do \"man cribbage\"");
109 }
110 }
111 playing = TRUE;
112 do {
113 wclrtobot(Msgwin);
114 msg(quiet ? "L or S? " : "Long (to 121) or Short (to 61)? ");
115 if (glimit == SGAME)
116 glimit = (getuchar() == 'L' ? LGAME : SGAME);
117 else
118 glimit = (getuchar() == 'S' ? SGAME : LGAME);
119 game();
120 msg("Another game? ");
121 playing = (getuchar() == 'Y');
122 } while (playing);
123
124 if (f = fopen(_PATH_LOG, "a")) {
125 (void)fprintf(f, "%s: won %5.5d, lost %5.5d\n",
126 getlogin(), cgames, pgames);
127 (void)fclose(f);
128 }
129 bye();
130 if (!f) {
131 (void)fprintf(stderr, "\ncribbage: can't open %s.\n",
132 _PATH_LOG);
133 exit(1);
134 }
135 exit(0);
136}
137
138/*
139 * makeboard:
140 * Print out the initial board on the screen
141 */
142makeboard()
143{
144 mvaddstr(SCORE_Y + 0, SCORE_X, "+---------------------------------------+");
145 mvaddstr(SCORE_Y + 1, SCORE_X, "| Score: 0 YOU |");
146 mvaddstr(SCORE_Y + 2, SCORE_X, "| *.....:.....:.....:.....:.....:..... |");
147 mvaddstr(SCORE_Y + 3, SCORE_X, "| *.....:.....:.....:.....:.....:..... |");
148 mvaddstr(SCORE_Y + 4, SCORE_X, "| |");
149 mvaddstr(SCORE_Y + 5, SCORE_X, "| *.....:.....:.....:.....:.....:..... |");
150 mvaddstr(SCORE_Y + 6, SCORE_X, "| *.....:.....:.....:.....:.....:..... |");
151 mvaddstr(SCORE_Y + 7, SCORE_X, "| Score: 0 ME |");
152 mvaddstr(SCORE_Y + 8, SCORE_X, "+---------------------------------------+");
153 gamescore();
154}
155
156/*
157 * gamescore:
158 * Print out the current game score
159 */
160gamescore()
161{
162 extern int Lastscore[];
163
164 if (pgames || cgames) {
165 mvprintw(SCORE_Y + 1, SCORE_X + 28, "Games: %3d", pgames);
166 mvprintw(SCORE_Y + 7, SCORE_X + 28, "Games: %3d", cgames);
167 }
168 Lastscore[0] = -1;
169 Lastscore[1] = -1;
170}
171
172/*
173 * game:
174 * Play one game up to glimit points. Actually, we only ASK the
175 * player what card to turn. We do a random one, anyway.
176 */
177game()
178{
179 register int i, j;
180 BOOLEAN flag;
181 BOOLEAN compcrib;
182
183 makeboard();
184 refresh();
185 makedeck(deck);
186 shuffle(deck);
187 if (gamecount == 0) {
188 flag = TRUE;
189 do {
190 if (!rflag) { /* player cuts deck */
191 msg(quiet ? "Cut for crib? " :
192 "Cut to see whose crib it is -- low card wins? ");
193 getline();
194 }
195 i = (rand() >> 4) % CARDS; /* random cut */
196 do { /* comp cuts deck */
197 j = (rand() >> 4) % CARDS;
198 } while (j == i);
199 addmsg(quiet ? "You cut " : "You cut the ");
200 msgcard(deck[i], FALSE);
201 endmsg();
202 addmsg(quiet ? "I cut " : "I cut the ");
203 msgcard(deck[j], FALSE);
204 endmsg();
205 flag = (deck[i].rank == deck[j].rank);
206 if (flag) {
207 msg(quiet ? "We tied..." :
208 "We tied and have to try again...");
209 shuffle(deck);
210 continue;
211 }
212 else
213 compcrib = (deck[i].rank > deck[j].rank);
214 } while (flag);
215 }
216 else {
217 werase(Tablewin);
218 wrefresh(Tablewin);
219 werase(Compwin);
220 wrefresh(Compwin);
221 msg("Loser (%s) gets first crib", (iwon ? "you" : "me"));
222 compcrib = !iwon;
223 }
224
225 pscore = cscore = 0;
226 flag = TRUE;
227 do {
228 shuffle(deck);
229 flag = !playhand(compcrib);
230 compcrib = !compcrib;
231 } while (flag);
232 ++gamecount;
233 if (cscore < pscore) {
234 if (glimit - cscore > 60) {
235 msg("YOU DOUBLE SKUNKED ME!");
236 pgames += 4;
237 }
238 else if (glimit - cscore > 30) {
239 msg("YOU SKUNKED ME!");
240 pgames += 2;
241 }
242 else {
243 msg("YOU WON!");
244 ++pgames;
245 }
246 iwon = FALSE;
247 }
248 else {
249 if (glimit - pscore > 60) {
250 msg("I DOUBLE SKUNKED YOU!");
251 cgames += 4;
252 }
253 else if (glimit - pscore > 30) {
254 msg("I SKUNKED YOU!");
255 cgames += 2;
256 }
257 else {
258 msg("I WON!");
259 ++cgames;
260 }
261 iwon = TRUE;
262 }
263 gamescore();
264}
265
266/*
267 * playhand:
268 * Do up one hand of the game
269 */
270playhand(mycrib)
271BOOLEAN mycrib;
272{
273 register int deckpos;
274 extern char Msgbuf[];
275
276 werase(Compwin);
277
278 knownum = 0;
279 deckpos = deal(mycrib);
280 sorthand(chand, FULLHAND);
281 sorthand(phand, FULLHAND);
282 makeknown(chand, FULLHAND);
283 prhand(phand, FULLHAND, Playwin, FALSE);
284 discard(mycrib);
285 if (cut(mycrib, deckpos))
286 return TRUE;
287 if (peg(mycrib))
288 return TRUE;
289 werase(Tablewin);
290 wrefresh(Tablewin);
291 if (score(mycrib))
292 return TRUE;
293 return FALSE;
294}
295
296
297
298/*
299 * deal cards to both players from deck
300 */
301
302deal( mycrib )
303{
304 register int i, j;
305
306 j = 0;
307 for( i = 0; i < FULLHAND; i++ ) {
308 if( mycrib ) {
309 phand[i] = deck[j++];
310 chand[i] = deck[j++];
311 }
312 else {
313 chand[i] = deck[j++];
314 phand[i] = deck[j++];
315 }
316 }
317 return( j );
318}
319
320/*
321 * discard:
322 * Handle players discarding into the crib...
323 * Note: we call cdiscard() after prining first message so player doesn't wait
324 */
325discard(mycrib)
326BOOLEAN mycrib;
327{
328 register char *prompt;
329 CARD crd;
330
331 prcrib(mycrib, TRUE);
332 prompt = (quiet ? "Discard --> " : "Discard a card --> ");
333 cdiscard(mycrib); /* puts best discard at end */
334 crd = phand[infrom(phand, FULLHAND, prompt)];
335 cremove(crd, phand, FULLHAND);
336 prhand(phand, FULLHAND, Playwin, FALSE);
337 crib[0] = crd;
338/* next four lines same as last four except for cdiscard() */
339 crd = phand[infrom(phand, FULLHAND - 1, prompt)];
340 cremove(crd, phand, FULLHAND - 1);
341 prhand(phand, FULLHAND, Playwin, FALSE);
342 crib[1] = crd;
343 crib[2] = chand[4];
344 crib[3] = chand[5];
345 chand[4].rank = chand[4].suit = chand[5].rank = chand[5].suit = EMPTY;
346}
347
348/*
349 * cut:
350 * Cut the deck and set turnover. Actually, we only ASK the
351 * player what card to turn. We do a random one, anyway.
352 */
353cut(mycrib, pos)
354BOOLEAN mycrib;
355int pos;
356{
357 register int i, cardx;
358 BOOLEAN win = FALSE;
359
360 if (mycrib) {
361 if (!rflag) { /* random cut */
362 msg(quiet ? "Cut the deck? " :
363 "How many cards down do you wish to cut the deck? ");
364 getline();
365 }
366 i = (rand() >> 4) % (CARDS - pos);
367 turnover = deck[i + pos];
368 addmsg(quiet ? "You cut " : "You cut the ");
369 msgcard(turnover, FALSE);
370 endmsg();
371 if (turnover.rank == JACK) {
372 msg("I get two for his heels");
373 win = chkscr(&cscore,2 );
374 }
375 }
376 else {
377 i = (rand() >> 4) % (CARDS - pos) + pos;
378 turnover = deck[i];
379 addmsg(quiet ? "I cut " : "I cut the ");
380 msgcard(turnover, FALSE);
381 endmsg();
382 if (turnover.rank == JACK) {
383 msg("You get two for his heels");
384 win = chkscr(&pscore, 2);
385 }
386 }
387 makeknown(&turnover, 1);
388 prcrib(mycrib, FALSE);
389 return win;
390}
391
392/*
393 * prcrib:
394 * Print out the turnover card with crib indicator
395 */
396prcrib(mycrib, blank)
397BOOLEAN mycrib, blank;
398{
399 register int y, cardx;
400
401 if (mycrib)
402 cardx = CRIB_X;
403 else
404 cardx = 0;
405
406 mvaddstr(CRIB_Y, cardx + 1, "CRIB");
407 prcard(stdscr, CRIB_Y + 1, cardx, turnover, blank);
408
409 if (mycrib)
410 cardx = 0;
411 else
412 cardx = CRIB_X;
413
414 for (y = CRIB_Y; y <= CRIB_Y + 5; y++)
415 mvaddstr(y, cardx, " ");
416}
417
418/*
419 * peg:
420 * Handle all the pegging...
421 */
422
423static CARD Table[14];
424
425static int Tcnt;
426
427peg(mycrib)
428BOOLEAN mycrib;
429{
430 static CARD ch[CINHAND], ph[CINHAND];
431 CARD crd;
432 register int i, j, k;
433 register int l;
434 register int cnum, pnum, sum;
435 register BOOLEAN myturn, mego, ugo, last, played;
436
437 cnum = pnum = CINHAND;
438 for (i = 0; i < CINHAND; i++) { /* make copies of hands */
439 ch[i] = chand[i];
440 ph[i] = phand[i];
441 }
442 Tcnt = 0; /* index to table of cards played */
443 sum = 0; /* sum of cards played */
444 mego = ugo = FALSE;
445 myturn = !mycrib;
446 for (;;) {
447 last = TRUE; /* enable last flag */
448 prhand(ph, pnum, Playwin, FALSE);
449 prhand(ch, cnum, Compwin, TRUE);
450 prtable(sum);
451 if (myturn) { /* my tyrn to play */
452 if (!anymove(ch, cnum, sum)) { /* if no card to play */
453 if (!mego && cnum) { /* go for comp? */
454 msg("GO");
455 mego = TRUE;
456 }
457 if (anymove(ph, pnum, sum)) /* can player move? */
458 myturn = !myturn;
459 else { /* give him his point */
460 msg(quiet ? "You get one" : "You get one point");
461 if (chkscr(&pscore, 1))
462 return TRUE;
463 sum = 0;
464 mego = ugo = FALSE;
465 Tcnt = 0;
466 }
467 }
468 else {
469 played = TRUE;
470 j = -1;
471 k = 0;
472 for (i = 0; i < cnum; i++) { /* maximize score */
473 l = pegscore(ch[i], Table, Tcnt, sum);
474 if (l > k) {
475 k = l;
476 j = i;
477 }
478 }
479 if (j < 0) /* if nothing scores */
480 j = cchose(ch, cnum, sum);
481 crd = ch[j];
482 cremove(crd, ch, cnum--);
483 sum += VAL(crd.rank);
484 Table[Tcnt++] = crd;
485 if (k > 0) {
486 addmsg(quiet ? "I get %d playing " :
487 "I get %d points playing ", k);
488 msgcard(crd, FALSE);
489 endmsg();
490 if (chkscr(&cscore, k))
491 return TRUE;
492 }
493 myturn = !myturn;
494 }
495 }
496 else {
497 if (!anymove(ph, pnum, sum)) { /* can player move? */
498 if (!ugo && pnum) { /* go for player */
499 msg("You have a GO");
500 ugo = TRUE;
501 }
502 if (anymove(ch, cnum, sum)) /* can computer play? */
503 myturn = !myturn;
504 else {
505 msg(quiet ? "I get one" : "I get one point");
506 do_wait();
507 if (chkscr(&cscore, 1))
508 return TRUE;
509 sum = 0;
510 mego = ugo = FALSE;
511 Tcnt = 0;
512 }
513 }
514 else { /* player plays */
515 played = FALSE;
516 if (pnum == 1) {
517 crd = ph[0];
518 msg("You play your last card");
519 }
520 else
521 for (;;) {
522 prhand(ph, pnum, Playwin, FALSE);
523 crd = ph[infrom(ph, pnum, "Your play: ")];
524 if (sum + VAL(crd.rank) <= 31)
525 break;
526 else
527 msg("Total > 31 -- try again");
528 }
529 makeknown(&crd, 1);
530 cremove(crd, ph, pnum--);
531 i = pegscore(crd, Table, Tcnt, sum);
532 sum += VAL(crd.rank);
533 Table[Tcnt++] = crd;
534 if (i > 0) {
535 msg(quiet ? "You got %d" : "You got %d points", i);
536 if (chkscr(&pscore, i))
537 return TRUE;
538 }
539 myturn = !myturn;
540 }
541 }
542 if (sum >= 31) {
543 if (!myturn)
544 do_wait();
545 sum = 0;
546 mego = ugo = FALSE;
547 Tcnt = 0;
548 last = FALSE; /* disable last flag */
549 }
550 if (!pnum && !cnum)
551 break; /* both done */
552 }
553 prhand(ph, pnum, Playwin, FALSE);
554 prhand(ch, cnum, Compwin, TRUE);
555 prtable(sum);
556 if (last)
557 if (played) {
558 msg(quiet ? "I get one for last" : "I get one point for last");
559 do_wait();
560 if (chkscr(&cscore, 1))
561 return TRUE;
562 }
563 else {
564 msg(quiet ? "You get one for last" :
565 "You get one point for last");
566 if (chkscr(&pscore, 1))
567 return TRUE;
568 }
569 return FALSE;
570}
571
572/*
573 * prtable:
574 * Print out the table with the current score
575 */
576prtable(score)
577int score;
578{
579 prhand(Table, Tcnt, Tablewin, FALSE);
580 mvwprintw(Tablewin, (Tcnt + 2) * 2, Tcnt + 1, "%2d", score);
581 wrefresh(Tablewin);
582}
583
584/*
585 * score:
586 * Handle the scoring of the hands
587 */
588score(mycrib)
589BOOLEAN mycrib;
590{
591 sorthand(crib, CINHAND);
592 if (mycrib) {
593 if (plyrhand(phand, "hand"))
594 return TRUE;
595 if (comphand(chand, "hand"))
596 return TRUE;
597 do_wait();
598 if (comphand(crib, "crib"))
599 return TRUE;
600 }
601 else {
602 if (comphand(chand, "hand"))
603 return TRUE;
604 if (plyrhand(phand, "hand"))
605 return TRUE;
606 if (plyrhand(crib, "crib"))
607 return TRUE;
608 }
609 return FALSE;
610}