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