Home | History | Annotate | Line # | Download | only in cribbage
crib.c revision 1.1
      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	"deck.h"
     47 # include	"cribbage.h"
     48 # include	"cribcur.h"
     49 # include	"pathnames.h"
     50 
     51 main(argc, argv)
     52 int	argc;
     53 char	*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  */
    142 makeboard()
    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  */
    160 gamescore()
    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  */
    177 game()
    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  */
    270 playhand(mycrib)
    271 BOOLEAN		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 
    302 deal( 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  */
    325 discard(mycrib)
    326 BOOLEAN		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  */
    353 cut(mycrib, pos)
    354 BOOLEAN		mycrib;
    355 int		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  */
    396 prcrib(mycrib, blank)
    397 BOOLEAN		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 
    423 static CARD		Table[14];
    424 
    425 static int		Tcnt;
    426 
    427 peg(mycrib)
    428 BOOLEAN		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  */
    576 prtable(score)
    577 int	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  */
    588 score(mycrib)
    589 BOOLEAN		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 }
    611