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