Path: uunet!tektronix!tekgen!tekred!games
From: games@tekred.TEK.COM
Newsgroups: comp.sources.games
Subject: v04i003: cribbage - 4.3BSD cribbage game, Part01/02
Message-ID: <2373@tekred.TEK.COM>
Date: 31 Mar 88 21:54:15 GMT
Sender: billr@tekred.TEK.COM
Lines: 2126
Approved: billr@saab.CNA.TEK.COM
Submitted by: bostic@okeeffe.Berkeley.EDU (Keith Bostic)
Comp.sources.games: Volume 4, Issue 3
Archive-name: cribbage/Part01
[Here is the legal source for the 4.3BSD cribbage game. Thanks
to Keith Bostic at Berkeley for making this available. -br]
#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh README <<'END_OF_README'
XThe Makefiles for these games require the "dm" program to install
X-- we've written a dungeon master program (hasn't everybody?) and they
Xexpect to have it around. They also require the "mkdep" program to
Xcreate dependencies. You probably want to note in the posting that
Xthe problems exist, and everybody should hack the Makefile.
X
XYour posting should credit Earl Cohen with writing the logic for cribbage,
Xand Ken Arnold with doing the screen interface.
X
X--keith
END_OF_README
if test 466 -ne `wc -c MANIFEST <<'END_OF_MANIFEST'
X File Name Archive # Description
X-----------------------------------------------------------
X MANIFEST 1 This shipping list
X Makefile 2
X README 1
X cards.c 2
X crib.c 1
X cribbage.6 1
X cribbage.h 2
X cribbage.n 1
X cribcur.h 1
X deck.h 2
X extern.c 2
X io.c 1
X macro 2
X score.c 1
X support.c 2
END_OF_MANIFEST
if test 564 -ne `wc -c crib.c <<'END_OF_crib.c'
X/*
X * Copyright (c) 1980 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that this notice is preserved and that due credit is given
X * to the University of California at Berkeley. The name of the University
X * may not be used to endorse or promote products derived from this
X * software without specific prior written permission. This software
X * is provided ``as is'' without express or implied warranty.
X */
X
X#ifndef lint
Xchar copyright[] =
X"@(#) Copyright (c) 1980 Regents of the University of California.\n\
X All rights reserved.\n";
X#endif /* not lint */
X
X#ifndef lint
Xstatic char sccsid[] = "@(#)crib.c 5.2 (Berkeley) 3/10/88";
X#endif /* not lint */
X
X# include
X# include
X# include "deck.h"
X# include "cribbage.h"
X# include "cribcur.h"
X
X
X# define LOGFILE "/usr/games/lib/criblog"
X# define INSTRCMD "ul /usr/games/lib/crib.instr | more -f"
X
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X register char *p;
X BOOLEAN playing;
X char *s; /* for reading arguments */
X char bust; /* flag for arg reader */
X FILE *f;
X FILE *fopen();
X char *getline();
X int bye();
X
X while (--argc > 0) {
X if ((*++argv)[0] != '-') {
X fprintf(stderr, "\n\ncribbage: usage is 'cribbage [-eqr]'\n");
X exit(1);
X }
X bust = FALSE;
X for (s = argv[0] + 1; *s != NULL; s++) {
X switch (*s) {
X case 'e':
X explain = TRUE;
X break;
X case 'q':
X quiet = TRUE;
X break;
X case 'r':
X rflag = TRUE;
X break;
X default:
X fprintf(stderr, "\n\ncribbage: usage is 'cribbage [-eqr]'\n");
X exit(2);
X break;
X }
X if (bust)
X break;
X }
X }
X
X initscr();
X signal(SIGINT, bye);
X crmode();
X noecho();
X Playwin = subwin(stdscr, PLAY_Y, PLAY_X, 0, 0);
X Tablewin = subwin(stdscr, TABLE_Y, TABLE_X, 0, PLAY_X);
X Compwin = subwin(stdscr, COMP_Y, COMP_X, 0, TABLE_X + PLAY_X);
X Msgwin = subwin(stdscr, MSG_Y, MSG_X, Y_MSG_START, SCORE_X + 1);
X leaveok(Playwin, TRUE);
X leaveok(Tablewin, TRUE);
X leaveok(Compwin, TRUE);
X clearok(stdscr, FALSE);
X
X if (!quiet) {
X msg("Do you need instructions for cribbage? ");
X if (getuchar() == 'Y') {
X endwin();
X fflush(stdout);
X system(INSTRCMD);
X crmode();
X noecho();
X clear();
X refresh();
X msg("For the rules of this program, do \"man cribbage\"");
X }
X }
X playing = TRUE;
X do {
X wclrtobot(Msgwin);
X msg(quiet ? "L or S? " : "Long (to 121) or Short (to 61)? ");
X if (glimit == SGAME)
X glimit = (getuchar() == 'L' ? LGAME : SGAME);
X else
X glimit = (getuchar() == 'S' ? SGAME : LGAME);
X game();
X msg("Another game? ");
X playing = (getuchar() == 'Y');
X } while (playing);
X
X if ((f = fopen(LOGFILE, "a")) != NULL) {
X fprintf(f, "Won %5.5d, Lost %5.5d\n", cgames, pgames);
X fclose(f);
X }
X
X bye();
X}
X
X/*
X * makeboard:
X * Print out the initial board on the screen
X */
Xmakeboard()
X{
X mvaddstr(SCORE_Y + 0, SCORE_X, "+---------------------------------------+");
X mvaddstr(SCORE_Y + 1, SCORE_X, "| Score: 0 YOU |");
X mvaddstr(SCORE_Y + 2, SCORE_X, "| *.....:.....:.....:.....:.....:..... |");
X mvaddstr(SCORE_Y + 3, SCORE_X, "| *.....:.....:.....:.....:.....:..... |");
X mvaddstr(SCORE_Y + 4, SCORE_X, "| |");
X mvaddstr(SCORE_Y + 5, SCORE_X, "| *.....:.....:.....:.....:.....:..... |");
X mvaddstr(SCORE_Y + 6, SCORE_X, "| *.....:.....:.....:.....:.....:..... |");
X mvaddstr(SCORE_Y + 7, SCORE_X, "| Score: 0 ME |");
X mvaddstr(SCORE_Y + 8, SCORE_X, "+---------------------------------------+");
X gamescore();
X}
X
X/*
X * gamescore:
X * Print out the current game score
X */
Xgamescore()
X{
X extern int Lastscore[];
X
X if (pgames || cgames) {
X mvprintw(SCORE_Y + 1, SCORE_X + 28, "Games: %3d", pgames);
X mvprintw(SCORE_Y + 7, SCORE_X + 28, "Games: %3d", cgames);
X }
X Lastscore[0] = -1;
X Lastscore[1] = -1;
X}
X
X/*
X * game:
X * Play one game up to glimit points. Actually, we only ASK the
X * player what card to turn. We do a random one, anyway.
X */
Xgame()
X{
X register int i, j;
X BOOLEAN flag;
X BOOLEAN compcrib;
X
X makeboard();
X refresh();
X makedeck(deck);
X shuffle(deck);
X if (gamecount == 0) {
X flag = TRUE;
X do {
X if (!rflag) { /* player cuts deck */
X msg(quiet ? "Cut for crib? " :
X "Cut to see whose crib it is -- low card wins? ");
X getline();
X }
X i = (rand() >> 4) % CARDS; /* random cut */
X do { /* comp cuts deck */
X j = (rand() >> 4) % CARDS;
X } while (j == i);
X addmsg(quiet ? "You cut " : "You cut the ");
X msgcard(deck[i], FALSE);
X endmsg();
X addmsg(quiet ? "I cut " : "I cut the ");
X msgcard(deck[j], FALSE);
X endmsg();
X flag = (deck[i].rank == deck[j].rank);
X if (flag) {
X msg(quiet ? "We tied..." :
X "We tied and have to try again...");
X shuffle(deck);
X continue;
X }
X else
X compcrib = (deck[i].rank > deck[j].rank);
X } while (flag);
X }
X else {
X werase(Tablewin);
X wrefresh(Tablewin);
X werase(Compwin);
X wrefresh(Compwin);
X msg("Loser (%s) gets first crib", (iwon ? "you" : "me"));
X compcrib = !iwon;
X }
X
X pscore = cscore = 0;
X flag = TRUE;
X do {
X shuffle(deck);
X flag = !playhand(compcrib);
X compcrib = !compcrib;
X } while (flag);
X ++gamecount;
X if (cscore < pscore) {
X if (glimit - cscore > 60) {
X msg("YOU DOUBLE SKUNKED ME!");
X pgames += 4;
X }
X else if (glimit - cscore > 30) {
X msg("YOU SKUNKED ME!");
X pgames += 2;
X }
X else {
X msg("YOU WON!");
X ++pgames;
X }
X iwon = FALSE;
X }
X else {
X if (glimit - pscore > 60) {
X msg("I DOUBLE SKUNKED YOU!");
X cgames += 4;
X }
X else if (glimit - pscore > 30) {
X msg("I SKUNKED YOU!");
X cgames += 2;
X }
X else {
X msg("I WON!");
X ++cgames;
X }
X iwon = TRUE;
X }
X gamescore();
X}
X
X/*
X * playhand:
X * Do up one hand of the game
X */
Xplayhand(mycrib)
XBOOLEAN mycrib;
X{
X register int deckpos;
X extern char Msgbuf[];
X
X werase(Compwin);
X
X knownum = 0;
X deckpos = deal(mycrib);
X sorthand(chand, FULLHAND);
X sorthand(phand, FULLHAND);
X makeknown(chand, FULLHAND);
X prhand(phand, FULLHAND, Playwin, FALSE);
X discard(mycrib);
X if (cut(mycrib, deckpos))
X return TRUE;
X if (peg(mycrib))
X return TRUE;
X werase(Tablewin);
X wrefresh(Tablewin);
X if (score(mycrib))
X return TRUE;
X return FALSE;
X}
X
X
X
X/*
X * deal cards to both players from deck
X */
X
Xdeal( mycrib )
X{
X register int i, j;
X
X j = 0;
X for( i = 0; i < FULLHAND; i++ ) {
X if( mycrib ) {
X phand[i] = deck[j++];
X chand[i] = deck[j++];
X }
X else {
X chand[i] = deck[j++];
X phand[i] = deck[j++];
X }
X }
X return( j );
X}
X
X/*
X * discard:
X * Handle players discarding into the crib...
X * Note: we call cdiscard() after prining first message so player doesn't wait
X */
Xdiscard(mycrib)
XBOOLEAN mycrib;
X{
X register char *prompt;
X CARD crd;
X
X prcrib(mycrib, TRUE);
X prompt = (quiet ? "Discard --> " : "Discard a card --> ");
X cdiscard(mycrib); /* puts best discard at end */
X crd = phand[infrom(phand, FULLHAND, prompt)];
X remove(crd, phand, FULLHAND);
X prhand(phand, FULLHAND, Playwin, FALSE);
X crib[0] = crd;
X/* next four lines same as last four except for cdiscard() */
X crd = phand[infrom(phand, FULLHAND - 1, prompt)];
X remove(crd, phand, FULLHAND - 1);
X prhand(phand, FULLHAND, Playwin, FALSE);
X crib[1] = crd;
X crib[2] = chand[4];
X crib[3] = chand[5];
X chand[4].rank = chand[4].suit = chand[5].rank = chand[5].suit = EMPTY;
X}
X
X/*
X * cut:
X * Cut the deck and set turnover. Actually, we only ASK the
X * player what card to turn. We do a random one, anyway.
X */
Xcut(mycrib, pos)
XBOOLEAN mycrib;
Xint pos;
X{
X register int i, cardx;
X BOOLEAN win = FALSE;
X
X if (mycrib) {
X if (!rflag) { /* random cut */
X msg(quiet ? "Cut the deck? " :
X "How many cards down do you wish to cut the deck? ");
X getline();
X }
X i = (rand() >> 4) % (CARDS - pos);
X turnover = deck[i + pos];
X addmsg(quiet ? "You cut " : "You cut the ");
X msgcard(turnover, FALSE);
X endmsg();
X if (turnover.rank == JACK) {
X msg("I get two for his heels");
X win = chkscr(&cscore,2 );
X }
X }
X else {
X i = (rand() >> 4) % (CARDS - pos) + pos;
X turnover = deck[i];
X addmsg(quiet ? "I cut " : "I cut the ");
X msgcard(turnover, FALSE);
X endmsg();
X if (turnover.rank == JACK) {
X msg("You get two for his heels");
X win = chkscr(&pscore, 2);
X }
X }
X makeknown(&turnover, 1);
X prcrib(mycrib, FALSE);
X return win;
X}
X
X/*
X * prcrib:
X * Print out the turnover card with crib indicator
X */
Xprcrib(mycrib, blank)
XBOOLEAN mycrib, blank;
X{
X register int y, cardx;
X
X if (mycrib)
X cardx = CRIB_X;
X else
X cardx = 0;
X
X mvaddstr(CRIB_Y, cardx + 1, "CRIB");
X prcard(stdscr, CRIB_Y + 1, cardx, turnover, blank);
X
X if (mycrib)
X cardx = 0;
X else
X cardx = CRIB_X;
X
X for (y = CRIB_Y; y <= CRIB_Y + 5; y++)
X mvaddstr(y, cardx, " ");
X}
X
X/*
X * peg:
X * Handle all the pegging...
X */
X
Xstatic CARD Table[14];
X
Xstatic int Tcnt;
X
Xpeg(mycrib)
XBOOLEAN mycrib;
X{
X static CARD ch[CINHAND], ph[CINHAND];
X CARD crd;
X register int i, j, k;
X register int l;
X register int cnum, pnum, sum;
X register BOOLEAN myturn, mego, ugo, last, played;
X
X cnum = pnum = CINHAND;
X for (i = 0; i < CINHAND; i++) { /* make copies of hands */
X ch[i] = chand[i];
X ph[i] = phand[i];
X }
X Tcnt = 0; /* index to table of cards played */
X sum = 0; /* sum of cards played */
X mego = ugo = FALSE;
X myturn = !mycrib;
X for (;;) {
X last = TRUE; /* enable last flag */
X prhand(ph, pnum, Playwin, FALSE);
X prhand(ch, cnum, Compwin, TRUE);
X prtable(sum);
X if (myturn) { /* my tyrn to play */
X if (!anymove(ch, cnum, sum)) { /* if no card to play */
X if (!mego && cnum) { /* go for comp? */
X msg("GO");
X mego = TRUE;
X }
X if (anymove(ph, pnum, sum)) /* can player move? */
X myturn = !myturn;
X else { /* give him his point */
X msg(quiet ? "You get one" : "You get one point");
X if (chkscr(&pscore, 1))
X return TRUE;
X sum = 0;
X mego = ugo = FALSE;
X Tcnt = 0;
X }
X }
X else {
X played = TRUE;
X j = -1;
X k = 0;
X for (i = 0; i < cnum; i++) { /* maximize score */
X l = pegscore(ch[i], Table, Tcnt, sum);
X if (l > k) {
X k = l;
X j = i;
X }
X }
X if (j < 0) /* if nothing scores */
X j = cchose(ch, cnum, sum);
X crd = ch[j];
X remove(crd, ch, cnum--);
X sum += VAL(crd.rank);
X Table[Tcnt++] = crd;
X if (k > 0) {
X addmsg(quiet ? "I get %d playing " :
X "I get %d points playing ", k);
X msgcard(crd, FALSE);
X endmsg();
X if (chkscr(&cscore, k))
X return TRUE;
X }
X myturn = !myturn;
X }
X }
X else {
X if (!anymove(ph, pnum, sum)) { /* can player move? */
X if (!ugo && pnum) { /* go for player */
X msg("You have a GO");
X ugo = TRUE;
X }
X if (anymove(ch, cnum, sum)) /* can computer play? */
X myturn = !myturn;
X else {
X msg(quiet ? "I get one" : "I get one point");
X do_wait();
X if (chkscr(&cscore, 1))
X return TRUE;
X sum = 0;
X mego = ugo = FALSE;
X Tcnt = 0;
X }
X }
X else { /* player plays */
X played = FALSE;
X if (pnum == 1) {
X crd = ph[0];
X msg("You play your last card");
X }
X else
X for (;;) {
X prhand(ph, pnum, Playwin, FALSE);
X crd = ph[infrom(ph, pnum, "Your play: ")];
X if (sum + VAL(crd.rank) <= 31)
X break;
X else
X msg("Total > 31 -- try again");
X }
X makeknown(&crd, 1);
X remove(crd, ph, pnum--);
X i = pegscore(crd, Table, Tcnt, sum);
X sum += VAL(crd.rank);
X Table[Tcnt++] = crd;
X if (i > 0) {
X msg(quiet ? "You got %d" : "You got %d points", i);
X if (chkscr(&pscore, i))
X return TRUE;
X }
X myturn = !myturn;
X }
X }
X if (sum >= 31) {
X if (!myturn)
X do_wait();
X sum = 0;
X mego = ugo = FALSE;
X Tcnt = 0;
X last = FALSE; /* disable last flag */
X }
X if (!pnum && !cnum)
X break; /* both done */
X }
X prhand(ph, pnum, Playwin, FALSE);
X prhand(ch, cnum, Compwin, TRUE);
X prtable(sum);
X if (last)
X if (played) {
X msg(quiet ? "I get one for last" : "I get one point for last");
X do_wait();
X if (chkscr(&cscore, 1))
X return TRUE;
X }
X else {
X msg(quiet ? "You get one for last" :
X "You get one point for last");
X if (chkscr(&pscore, 1))
X return TRUE;
X }
X return FALSE;
X}
X
X/*
X * prtable:
X * Print out the table with the current score
X */
Xprtable(score)
Xint score;
X{
X prhand(Table, Tcnt, Tablewin, FALSE);
X mvwprintw(Tablewin, (Tcnt + 2) * 2, Tcnt + 1, "%2d", score);
X wrefresh(Tablewin);
X}
X
X/*
X * score:
X * Handle the scoring of the hands
X */
Xscore(mycrib)
XBOOLEAN mycrib;
X{
X sorthand(crib, CINHAND);
X if (mycrib) {
X if (plyrhand(phand, "hand"))
X return TRUE;
X if (comphand(chand, "hand"))
X return TRUE;
X do_wait();
X if (comphand(crib, "crib"))
X return TRUE;
X }
X else {
X if (comphand(chand, "hand"))
X return TRUE;
X if (plyrhand(phand, "hand"))
X return TRUE;
X if (plyrhand(crib, "crib"))
X return TRUE;
X }
X return FALSE;
X}
END_OF_crib.c
if test 13125 -ne `wc -c cribbage.6 <<'END_OF_cribbage.6'
X.\" Copyright (c) 1980 Regents of the University of California.
X.\" All rights reserved.
X.\"
X.\" Redistribution and use in source and binary forms are permitted
X.\" provided that this notice is preserved and that due credit is given
X.\" to the University of California at Berkeley. The name of the University
X.\" may not be used to endorse or promote products derived from this
X.\" software without specific prior written permission. This software
X.\" is provided ``as is'' without express or implied warranty.
X.\"
X.\" @(#)cribbage.6 6.3 (Berkeley) 3/10/88
X.\"
X.TH CRIBBAGE 6 "March 10, 1988"
X.UC 4
X.SH NAME
Xcribbage \- the card game cribbage
X.SH SYNOPSIS
X.B /usr/games/cribbage
X[
X.B \-req
X]
X.I name ...
X.SH DESCRIPTION
X.I Cribbage
Xplays the card game cribbage, with the program playing one hand
Xand the user the other. The program will initially ask the user if
Xthe rules of the game are needed \- if so, it will print out
Xthe appropriate section from
X.I According to Hoyle
Xwith
X.I more (I).
X.PP
X.I Cribbage
Xoptions include:
X.TP
X.B \-e
XWhen the player makes a mistake scoring his hand or crib, provide an
Xexplanation of the correct score. (This is especially useful for
Xbeginning players.)
X.TP
X.B \-q
XPrint a shorter form of all messages \- this is only recommended for
Xusers who have played the game without specifying this option.
X.TP
X.B \-r
XInstead of asking the player to cut the deck, the program will randomly
Xcut the deck.
X.PP
X.I Cribbage
Xfirst asks the player whether he wishes to play a short game
X(\*(lqonce around\*(rq, to 61) or a long game (\*(lqtwice around\*(rq, to 121). A
Xresponse of `s' will result in a short game, any other response will
Xplay a long game.
X.PP
XAt the start of the first game, the program
Xasks the player to cut the deck to determine who gets the
Xfirst crib. The user should respond with a number between 0 and
X51, indicating how many cards down the deck is to be cut. The player
Xwho cuts the lower ranked card gets the first crib.
XIf more than one game is played, the
Xloser of the previous game gets the first crib in the current game.
X.PP
XFor each hand, the program first prints the player's hand,
Xwhose crib it is, and then asks the player
Xto discard two cards into the crib. The cards are prompted for
Xone per line, and are typed as explained below.
X.PP
XAfter discarding, the program cuts the deck (if it is the player's
Xcrib) or asks the player to cut the deck (if it's its crib); in the latter
Xcase, the appropriate response is a number from 0 to 39 indicating
Xhow far down the remaining 40 cards are to be cut.
X.PP
XAfter cutting the deck, play starts with the non-dealer (the person
Xwho doesn't have the crib) leading the first card.
XPlay continues, as per cribbage, until all cards are exhausted. The
Xprogram keeps track of the scoring of all points and the total of
Xthe cards on the table.
X.PP
XAfter play, the hands are scored. The program requests the player to
Xscore his hand (and the crib, if it is his) by printing out the
Xappropriate cards (and the cut card enclosed in brackets).
XPlay continues until one player reaches the game limit (61 or 121).
X.PP
XA carriage return when a numeric input is expected is equivalent
Xto typing the lowest legal value; when cutting the deck this
Xis equivalent to choosing the top card.
X.PP
XCards are specified as rank followed by suit. The ranks may be specified
Xas one of:
X`a', `2', `3', `4', `5', `6', `7', `8', `9', `t', `j', `q', and `k',
Xor alternatively, one of: \*(lqace\*(rq, \*(lqtwo\*(rq, \*(lqthree\*(rq, \*(lqfour\*(rq, \*(lqfive\*(rq, \*(lqsix\*(rq,
X\*(lqseven\*(rq, \*(lqeight\*(rq, \*(lqnine\*(rq, \*(lqten\*(rq, \*(lqjack\*(rq, \*(lqqueen\*(rq, and \*(lqking\*(rq.
XSuits may be specified as: `s', `h', `d', and `c', or alternatively as:
X\*(lqspades\*(rq, \*(lqhearts\*(rq, \*(lqdiamonds\*(rq, and \*(lqclubs\*(rq.
XA card may be specified as: \*(lq \*(rq , or: \*(lq of \*(rq .
XIf the single letter rank and suit designations are used, the space
Xseparating the suit and rank may be left out. Also, if only one card
Xof the desired rank is playable, typing the rank is sufficient.
XFor example, if your hand was \*(lq2H, 4D, 5C, 6H, JC, KD\*(rq and it was
Xdesired to discard the king of diamonds, any of the following could be typed:
X\*(lqk\*(rq, \*(lqking\*(rq, \*(lqkd\*(rq, \*(lqk d\*(rq, \*(lqk of d\*(rq, \*(lqking d\*(rq, \*(lqking of d\*(rq, \*(lqk diamonds\*(rq,
X\*(lqk of diamonds\*(rq, \*(lqking diamonds\*(rq, or \*(lqking of diamonds\*(rq.
X.SH FILES
X.ta 2i
X/usr/games/cribbage
X.SH AUTHORS
XEarl T. Cohen wrote the logic.
XKen Arnold added the screen oriented interface.
END_OF_cribbage.6
if test 4611 -ne `wc -c cribbage.n <<'END_OF_cribbage.n'
X.\" Copyright (c) 1980 Regents of the University of California.
X.\" All rights reserved. The Berkeley software License Agreement
X.\" specifies the terms and conditions for redistribution.
X.\"
X.\" @(#)cribbage.n 5.1 (Berkeley) 5/30/85
X.\"
X.so macro
X.na
X.PH "CRIBBAGE"
X.sp 2
X.ce
Xfrom
X.sp
X.ce
X.ul
XAccording to Hoyle
X.sp 2
X.PG
XCribbage is believed to have been invented by Sir John Suckling (1609-1642).
XProbably it is an elaboration of an older game, Noddy. The original game was
Xplayed with hands of five cards; the modern game gives each player six. That
Xis virtually the only change from Suckling's directions.
X.HP "Players."
XTwo. There are variants for three and four players, described later.
X.HP "Cards."
XThe pack of 52. The cards in each suit rank: K (high), Q, J, 10, 9, 8,
X7, 6, 5, 4, 3, 2, A. The
X.ul
Xcounting values
Xare: K, Q, J, 10, each 10 (wherefore these are called
X.ul
Xtenth cards);
Xace, 1; each other card, its index value.
X.HP "Cribbage Board".
XIndispensable to scoring (unless you have a computer!, ed.) is the device
Xknown as the
X.ul
Xcribbage board.
XThis is a rectangular panel, long and narrow, in which are
Xfour rows of 30 holes each. (See illustration.) At one end, or in the center,
Xare two or four additional holes, called
X.ul
Xgame holes.
XThe board is placed between the two players, and each keeps his own score on
Xthe two rows of holes nearest himself. Each is supplied with two
X.ul
Xpegs.
XBefore the first hand, the pegs are placed in the game holes. On
Xmaking his first score, the player advances one peg an appropriate number
Xof holes (one per point) away from the
X.ul
Xgame end
Xof the board. The second score is recorded by placing the second peg an
Xappropriate distance ahead of the first. For each subsequent score, the
Xrear peg is jumped ahead of the other, the distance between the two pegs
Xalways showing the amount of this last score.
X.PG
XThe traditional mode of scoring is down (away from the game end) the
Xouter row, and up the inner row. "Once around" is a game of 61 points.
X"Twice around" is a game of 121 points.
X.HP "Preliminaries."
XCards are drawn; the lower deals first. If cards of equal rank are drawn,
Xboth players draw again. Dealer has the right to shuffle last. Nondealer
Xcuts, and must leave at least four cards in each packet.
X.HP "Dealing."
XEach player receives six cards, dealt one at a time face down, beginning
Xwith the nondealer. The turn to deal alternates. The dealer has an
Xadvantage.
X.HP "Laying Away."
XAfter seeing his hand, each player
X.ul
Xlays away
Xtwo cards face down. The four cards laid away, placed in one pile, form the
X.ul
Xcrib.
XThe crib counts for the dealer. Nondealer therefore tries to lay away
X.ul
Xbalking cards --
Xcards that are least likely to create a score in the crib.
X.HP "The Starter."
XAfter both hands have laid away, nondealer lifts off a packet from the top
Xof the
X.ul
Xstock
X(the rest of the pack). Again, each packet must contain at least four cards.
XDealer turns up the top card of the lower packer, which is then placed on
Xtop of the stock when the packets are reunited. The card thus turned up is
Xcalled
X.ul
X1 the starter.
XIf it is a jack, dealer immediately pegs 2, called
X.ul
X2 for his heels.
X.HP "The Play."
XNondealer begins the play by laying a card from his hand face up on the
Xtable, announcing its counting value. Dealer then shows a card, announcing
Xthe total count of the two cards. Play continues in the same way, by
Xalternate exposure of cards, each player announcing the new total count.
XThe total may be carried only to 31, no further. If a player adds a card
Xthat brings the total exactly to 31, he pegs 2. If a player is unable to
Xplay another card without exceeding 31, he must say "Go," and his opponent
Xpegs 1, but before doing so, opponent must lay down any additional cards he
Xcan without exceeding 31. If such additional cards bring the total to
Xexactly 31, he pegs 2 instead of 1.
X.PG
XWhenever a
X.ul
Xgo
Xoccurs, the opponent of the player who played the last card must lead for a
Xnew count starting at zero. Playing the last card of all counts as a go.
X(Since nondealer makes the opening lead, dealer is bound to peg at least
X1 in play.)
X.PG
XBesides pegging for 31 and go, the player may also peg for certain
Xcombinations made in play, as follows:
X.sp 2
X.ti +4
X.ul
XFifteen.
X.IP
XMaking the count total 15 pegs 2.
X.EP
X.sp 2
X.ti +4
X.ul
XPair.
X.IP
XPlaying a card of same rank as that previously played pegs 2. Playing
Xa third card of the same rank makes
X.ul
Xpair royal
Xand pegs 6. Playing the fourth card of the same rank makes
X.ul
Xdouble pair royal
Xand pegs 12.
X.PG
XThe tenth cards pair strictly by rank, a king with a king, a queen with a
Xqueen, and so on. (King and jack do not make a pair, although each has
Xthe counting value 10.)
X.EP
X.sp 2
X.ti +4
X.ul
XRun.
X.IP
XPlaying a card which, with the two or more played immediately previously,
Xmakes a sequence of three or more cards, pegs 1 for each card in the
X.ul
Xrun.
XRuns depend on rank alone; the suits do not matter. Nor does the score
Xfor run depend upon playing the cards in strict sequence, so long as
Xthe three or more last cards played can be arranged in a run.
X.ul
XExample:
X7, 6, 8 played in that order score 3 for run; 5, 2, 4, 3 played in that order
Xscore 4 for run.
X.EP
X.PG
XAny of the foregoing combinations count, whether the cards are played
Xalternately or one player plays several times in succession in consequence
Xof a go. But a combination does not score if it is interrupted by a go.
X.HP "Showing."
XAfter the play, the hands are
X.ul
Xshown
X(counted). Nondealer shows first, then dealer's hand, then crib.
XThe starter is deemed to belong to each hand, so that each hand includes
Xfive cards. Combinations of scoring value are as follows:
X.sp 2
X.ti +4
X.ul
XFifteen.
X.IP
XEach combinations of two or more cards that total fifteen scores 2.
X.EP
X.sp 2
X.ti +4
X.ul
XPair.
X.IP
XEach pair of cards of the same rank scores 2.
X.EP
X.sp 2
X.ti +4
X.ul
XRun.
X.IP
XEach combination of three or more cards in sequence scores 1 for each card
Xin the run.
X.EP
X.sp 2
X.ti +4
X.ul
XFlush.
X.IP
XFour cards of the same suit in hand score 4; four cards in hand or crib
Xof same suit as the starter score 5. (No count for four-flush in crib.)
X.EP
X.sp 2
X.ti +4
X.ul
XHis Nobs.
X.IP
XJack of same suit as the starter, in hand or crib, scores 1.
X.EP
X.PG
XIt is important to note that every separate grouping of cards that makes
Xa fifteen, pair, or run counts separately. Three of a kind,
X.ul
Xpair royal,
Xcounts 6 because three sets of pairs can be made; similarly, four of a
Xkind,
X.ul
Xdouble pair royal,
Xcontain six pairs and count 12.
X.PG
XThe highest possible hand is J, 5, 5, 5 with the starter the 5 of the same
Xsuit as the jack. There are four fifteens by combining the jack with a
Xfive, four more by combinations of three fives (a total of 16 for fifteens);
Xthe double pair royal adds 12 for a total of 28; and
X.ul
Xhis nobs
Xadds 1 for a maximum score of 29. (the score of 2 for
X.ul
Xhis heels
Xdoes not count in the total of the hand, since it is pegged before the play.)
X.PG
XA
X.ul
Xdouble run
Xis a run with one card duplicated, as 4-3-3-2. Exclusive of fifteens, a
Xdouble run of three cards counts 8; of four cards, 10. A
X.ul
Xtriple run
Xis a run of three with one card triplicated, as K-K-K-Q-J. Exclusive of
Xfifteens, it counts 15. A
X.ul
Xquadruple run
Xis a run of three with two different cards duplicated, as the example
X8-8-7-6-6 previously given. Exclusive of fifteens, it counts 16.
X.PG
XNo hand can be constructed that counts 19, 25, 26 or 27. A time-honored
Xway of showing a hand with not a single counting combination is to say
X"I have nineteen."
X.PG
XThe customary oder in showing is to count fifteens first, then runs, then
Xpairs, but there is no compulsion of law.
X.ul
XExample:
XA hand (with starter) of 9-6-5-4-4 will usually be counted "Fifteen 2,
Xfifteen 4, fifteen 6 and double run makes 14," or simply "Fifteen 6 and
X8 is 14."
X.HP "Muggins."
XThe hands and crib are counted aloud, and if a player claims a greater
Xtotal than is due him, his opponent may require correction. In some
Xlocalities, if a player claims less than is due, his opponent may say
X"Muggins" and himself score the points overlooked.
X.HP "Scoring."
XThe usual
X.ul
Xgame
Xis 121, but it may be set at 61 by agreement. Since the player wins
Xwho first returns to the game hole by going "twice around," the scores
Xmust be pegged strictly in order: his heels, pegging in play, non-dealer's
Xhand, dealer's hand, crib. Thus, if nondealer goes out on showing his
Xhand, he wins, even though dealer might have gone out with a greater
Xtotal if allowed to count his hand and crib.
X.PG
XWhen the game of 121 is played for a stake, a player wins a single game
Xif the loser makes 61 points or more. If the loser fails to reach
X61, he is
X.ul
Xlurched,
Xand the other wins a double game.
X.HP "Irregularities."
X.ul
XMisdeal.
XThere must be a new deal by the same dealer if a card is found faced in the
Xpack, if a card is exposed in dealing, or if the pack be found imperfect.
X.PG
X.ul
XWrong Number of Cards.
XIf one hand (not crib) is found to have the wrong number of cards after
Xlaying away for the crib, the other hand and crib being correct, the
Xopponent may either demand a new deal or may peg 2 and rectify the
Xhand. If the crib is incorrect, both hands being correct, nondealer
Xpegs 2 and the crib is corrected.
X.HP "Error in Pegging."
XIf a player places a peg short of the amount to which he is entitled, he
Xmay not correct his error after he has played the next card or after the
Xcut for the next deal. If he pegs more than his announced score,
Xthe error must be corrected on demand at any time before the cut for the
Xnext deal and his opponent pegs 2.
X.HP "Strategy."
XThe best balking cards are kings and aces, because they have the least
Xchance of producing sequences. Tenth cards are generally good, provided
Xthat the two cards laid away are not too
X.ul
Xnear
X(likely to make a sequence). When nothing better offers, give two
X.ul
Xwide
Xcards -- at least three apart in rank.
X.PG
XProverbially the safest lead is a 4. The next card cannot make a 15.
XLower cards are also safe from this point of view, but are better
Xtreasured for go and 31. The most dangerous leads are 7 and 8, but
Xmay be made to trap the opponent when they are backed with other
Xclose cards. Generally speaking, play
X.ul
Xon
X(toward a sequence) when you have close cards and
X.ul
Xoff
Xwhen you do not. However, the state of the score is a consideration.
XIf far behind, play on when there is any chance of building a score
Xfor yourself; if well ahead, balk your opponent by playing off unless
Xyou will surely peg as much as he by playing on.
END_OF_cribbage.n
if test 10652 -ne `wc -c cribcur.h <<'END_OF_cribcur.h'
X/*
X * Copyright (c) 1980 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that this notice is preserved and that due credit is given
X * to the University of California at Berkeley. The name of the University
X * may not be used to endorse or promote products derived from this
X * software without specific prior written permission. This software
X * is provided ``as is'' without express or implied warranty.
X *
X * @(#)cribcur.h 5.2 (Berkeley) 3/10/88
X */
X
X# define PLAY_Y 15 /* size of player's hand window */
X# define PLAY_X 12
X# define TABLE_Y 21 /* size of table window */
X# define TABLE_X 14
X# define COMP_Y 15 /* size of computer's hand window */
X# define COMP_X 12
X# define Y_SCORE_SZ 9 /* Y size of score board */
X# define X_SCORE_SZ 41 /* X size of score board */
X# define SCORE_Y 0 /* starting position of scoring board */
X# define SCORE_X (PLAY_X + TABLE_X + COMP_X)
X# define CRIB_Y 17 /* position of crib (cut card) */
X# define CRIB_X (PLAY_X + TABLE_X)
X# define MSG_Y (LINES - (Y_SCORE_SZ + 1))
X# define MSG_X (COLS - SCORE_X - 1)
X# define Y_MSG_START (Y_SCORE_SZ + 1)
X
X# define PEG '*' /* what a peg looks like on the board */
X
Xextern WINDOW *Compwin; /* computer's hand window */
Xextern WINDOW *Msgwin; /* message window */
Xextern WINDOW *Playwin; /* player's hand window */
Xextern WINDOW *Tablewin; /* table window */
END_OF_cribcur.h
if test 1451 -ne `wc -c io.c <<'END_OF_io.c'
X/*
X * Copyright (c) 1980 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that this notice is preserved and that due credit is given
X * to the University of California at Berkeley. The name of the University
X * may not be used to endorse or promote products derived from this
X * software without specific prior written permission. This software
X * is provided ``as is'' without express or implied warranty.
X */
X
X#ifndef lint
Xstatic char sccsid[] = "@(#)io.c 5.3 (Berkeley) 3/10/88";
X#endif /* not lint */
X
X# include
X# include
X# include
X# include "deck.h"
X# include "cribbage.h"
X# include "cribcur.h"
X
X# define LINESIZE 128
X
X# ifdef CTRL
X# undef CTRL
X# endif
X# define CTRL(X) ('X' - 'A' + 1)
X
X# ifdef notdef /* defined in curses.h */
X# define erasechar() _tty.sg_erase
X# define killchar() _tty.sg_kill
X# endif
X
Xchar linebuf[ LINESIZE ];
X
Xchar *rankname[ RANKS ] = { "ACE", "TWO", "THREE", "FOUR",
X "FIVE", "SIX", "SEVEN", "EIGHT",
X "NINE", "TEN", "JACK", "QUEEN",
X "KING" };
X
Xchar *rankchar[ RANKS ] = { "A", "2", "3", "4", "5", "6", "7",
X "8", "9", "T", "J", "Q", "K" };
X
Xchar *suitname[ SUITS ] = { "SPADES", "HEARTS", "DIAMONDS",
X "CLUBS" };
X
Xchar *suitchar[ SUITS ] = { "S", "H", "D", "C" };
X
X
X
X/*
X * msgcard:
X * Call msgcrd in one of two forms
X */
Xmsgcard(c, brief)
XCARD c;
XBOOLEAN brief;
X{
X if (brief)
X return msgcrd(c, TRUE, (char *) NULL, TRUE);
X else
X return msgcrd(c, FALSE, " of ", FALSE);
X}
X
X
X
X/*
X * msgcrd:
X * Print the value of a card in ascii
X */
Xmsgcrd(c, brfrank, mid, brfsuit)
XCARD c;
Xchar *mid;
XBOOLEAN brfrank, brfsuit;
X{
X if (c.rank == EMPTY || c.suit == EMPTY)
X return FALSE;
X if (brfrank)
X addmsg("%1.1s", rankchar[c.rank]);
X else
X addmsg(rankname[c.rank]);
X if (mid != NULL)
X addmsg(mid);
X if (brfsuit)
X addmsg("%1.1s", suitchar[c.suit]);
X else
X addmsg(suitname[c.suit]);
X return TRUE;
X}
X
X/*
X * printcard:
X * Print out a card.
X */
Xprintcard(win, cardno, c, blank)
XWINDOW *win;
Xint cardno;
XCARD c;
XBOOLEAN blank;
X{
X prcard(win, cardno * 2, cardno, c, blank);
X}
X
X/*
X * prcard:
X * Print out a card on the window at the specified location
X */
Xprcard(win, y, x, c, blank)
XWINDOW *win;
Xint y, x;
XCARD c;
XBOOLEAN blank;
X{
X if (c.rank == EMPTY)
X return;
X mvwaddstr(win, y + 0, x, "+-----+");
X mvwaddstr(win, y + 1, x, "| |");
X mvwaddstr(win, y + 2, x, "| |");
X mvwaddstr(win, y + 3, x, "| |");
X mvwaddstr(win, y + 4, x, "+-----+");
X if (!blank) {
X mvwaddch(win, y + 1, x + 1, rankchar[c.rank][0]);
X waddch(win, suitchar[c.suit][0]);
X mvwaddch(win, y + 3, x + 4, rankchar[c.rank][0]);
X waddch(win, suitchar[c.suit][0]);
X }
X}
X
X/*
X * prhand:
X * Print a hand of n cards
X */
Xprhand(h, n, win, blank)
XCARD h[];
Xint n;
XWINDOW *win;
XBOOLEAN blank;
X{
X register int i;
X
X werase(win);
X for (i = 0; i < n; i++)
X printcard(win, i, *h++, blank);
X wrefresh(win);
X}
X
X
X
X/*
X * infrom:
X * reads a card, supposedly in hand, accepting unambigous brief
X * input, returns the index of the card found...
X */
Xinfrom(hand, n, prompt)
XCARD hand[];
Xint n;
Xchar *prompt;
X{
X register int i, j;
X CARD crd;
X
X if (n < 1) {
X printf("\nINFROM: %d = n < 1!!\n", n);
X exit(74);
X }
X for (;;) {
X msg(prompt);
X if (incard(&crd)) { /* if card is full card */
X if (!isone(crd, hand, n))
X msg("That's not in your hand");
X else {
X for (i = 0; i < n; i++)
X if (hand[i].rank == crd.rank &&
X hand[i].suit == crd.suit)
X break;
X if (i >= n) {
X printf("\nINFROM: isone or something messed up\n");
X exit(77);
X }
X return i;
X }
X }
X else /* if not full card... */
X if (crd.rank != EMPTY) {
X for (i = 0; i < n; i++)
X if (hand[i].rank == crd.rank)
X break;
X if (i >= n)
X msg("No such rank in your hand");
X else {
X for (j = i + 1; j < n; j++)
X if (hand[j].rank == crd.rank)
X break;
X if (j < n)
X msg("Ambiguous rank");
X else
X return i;
X }
X }
X else
X msg("Sorry, I missed that");
X }
X /* NOTREACHED */
X}
X
X
X
X/*
X * incard:
X * Inputs a card in any format. It reads a line ending with a CR
X * and then parses it.
X */
Xincard(crd)
XCARD *crd;
X{
X char *getline();
X register int i;
X int rnk, sut;
X char *line, *p, *p1;
X BOOLEAN retval;
X
X retval = FALSE;
X rnk = sut = EMPTY;
X if (!(line = getline()))
X goto gotit;
X p = p1 = line;
X while( *p1 != ' ' && *p1 != NULL ) ++p1;
X *p1++ = NULL;
X if( *p == NULL ) goto gotit;
X /* IMPORTANT: no real card has 2 char first name */
X if( strlen(p) == 2 ) { /* check for short form */
X rnk = EMPTY;
X for( i = 0; i < RANKS; i++ ) {
X if( *p == *rankchar[i] ) {
X rnk = i;
X break;
X }
X }
X if( rnk == EMPTY ) goto gotit; /* it's nothing... */
X ++p; /* advance to next char */
X sut = EMPTY;
X for( i = 0; i < SUITS; i++ ) {
X if( *p == *suitchar[i] ) {
X sut = i;
X break;
X }
X }
X if( sut != EMPTY ) retval = TRUE;
X goto gotit;
X }
X rnk = EMPTY;
X for( i = 0; i < RANKS; i++ ) {
X if( !strcmp( p, rankname[i] ) || !strcmp( p, rankchar[i] ) ) {
X rnk = i;
X break;
X }
X }
X if( rnk == EMPTY ) goto gotit;
X p = p1;
X while( *p1 != ' ' && *p1 != NULL ) ++p1;
X *p1++ = NULL;
X if( *p == NULL ) goto gotit;
X if( !strcmp( "OF", p ) ) {
X p = p1;
X while( *p1 != ' ' && *p1 != NULL ) ++p1;
X *p1++ = NULL;
X if( *p == NULL ) goto gotit;
X }
X sut = EMPTY;
X for( i = 0; i < SUITS; i++ ) {
X if( !strcmp( p, suitname[i] ) || !strcmp( p, suitchar[i] ) ) {
X sut = i;
X break;
X }
X }
X if( sut != EMPTY ) retval = TRUE;
Xgotit:
X (*crd).rank = rnk;
X (*crd).suit = sut;
X return( retval );
X}
X
X
X
X/*
X * getuchar:
X * Reads and converts to upper case
X */
Xgetuchar()
X{
X register int c;
X
X c = readchar();
X if (islower(c))
X c = toupper(c);
X waddch(Msgwin, c);
X return c;
X}
X
X/*
X * number:
X * Reads in a decimal number and makes sure it is between "lo" and
X * "hi" inclusive.
X */
Xnumber(lo, hi, prompt)
Xint lo, hi;
Xchar *prompt;
X{
X char *getline();
X register char *p;
X register int sum;
X
X sum = 0;
X for (;;) {
X msg(prompt);
X if(!(p = getline()) || *p == NULL) {
X msg(quiet ? "Not a number" : "That doesn't look like a number");
X continue;
X }
X sum = 0;
X
X if (!isdigit(*p))
X sum = lo - 1;
X else
X while (isdigit(*p)) {
X sum = 10 * sum + (*p - '0');
X ++p;
X }
X
X if (*p != ' ' && *p != '\t' && *p != NULL)
X sum = lo - 1;
X if (sum >= lo && sum <= hi)
X return sum;
X if (sum == lo - 1)
X msg("that doesn't look like a number, try again --> ");
X else
X msg("%d is not between %d and %d inclusive, try again --> ",
X sum, lo, hi);
X }
X}
X
X/*
X * msg:
X * Display a message at the top of the screen.
X */
Xchar Msgbuf[BUFSIZ] = { '\0' };
X
Xint Mpos = 0;
X
Xstatic int Newpos = 0;
X
X/* VARARGS1 */
Xmsg(fmt, args)
Xchar *fmt;
Xint args;
X{
X doadd(fmt, &args);
X endmsg();
X}
X
X/*
X * addmsg:
X * Add things to the current message
X */
X/* VARARGS1 */
Xaddmsg(fmt, args)
Xchar *fmt;
Xint args;
X{
X doadd(fmt, &args);
X}
X
X/*
X * endmsg:
X * Display a new msg.
X */
X
Xint Lineno = 0;
X
Xendmsg()
X{
X register int len;
X register char *mp, *omp;
X static int lastline = 0;
X
X /*
X * All messages should start with uppercase
X */
X mvaddch(lastline + Y_MSG_START, SCORE_X, ' ');
X if (islower(Msgbuf[0]) && Msgbuf[1] != ')')
X Msgbuf[0] = toupper(Msgbuf[0]);
X mp = Msgbuf;
X len = strlen(mp);
X if (len / MSG_X + Lineno >= MSG_Y) {
X while (Lineno < MSG_Y) {
X wmove(Msgwin, Lineno++, 0);
X wclrtoeol(Msgwin);
X }
X Lineno = 0;
X }
X mvaddch(Lineno + Y_MSG_START, SCORE_X, '*');
X lastline = Lineno;
X do {
X mvwaddstr(Msgwin, Lineno, 0, mp);
X if ((len = strlen(mp)) > MSG_X) {
X omp = mp;
X for (mp = &mp[MSG_X-1]; *mp != ' '; mp--)
X continue;
X while (*mp == ' ')
X mp--;
X mp++;
X wmove(Msgwin, Lineno, mp - omp);
X wclrtoeol(Msgwin);
X }
X if (++Lineno >= MSG_Y)
X Lineno = 0;
X } while (len > MSG_X);
X wclrtoeol(Msgwin);
X Mpos = len;
X Newpos = 0;
X wrefresh(Msgwin);
X refresh();
X wrefresh(Msgwin);
X}
X
X/*
X * doadd:
X * Perform an add onto the message buffer
X */
Xdoadd(fmt, args)
Xchar *fmt;
Xint *args;
X{
X static FILE junk;
X
X /*
X * Do the printf into Msgbuf
X */
X junk._flag = _IOWRT + _IOSTRG;
X junk._ptr = &Msgbuf[Newpos];
X junk._cnt = 32767;
X _doprnt(fmt, args, &junk);
X putc('\0', &junk);
X Newpos = strlen(Msgbuf);
X}
X
X/*
X * do_wait:
X * Wait for the user to type ' ' before doing anything else
X */
Xdo_wait()
X{
X register int line;
X static char prompt[] = { '-', '-', 'M', 'o', 'r', 'e', '-', '-', '\0' };
X
X if (Mpos + sizeof prompt < MSG_X)
X wmove(Msgwin, Lineno > 0 ? Lineno - 1 : MSG_Y - 1, Mpos);
X else {
X mvwaddch(Msgwin, Lineno, 0, ' ');
X wclrtoeol(Msgwin);
X if (++Lineno >= MSG_Y)
X Lineno = 0;
X }
X waddstr(Msgwin, prompt);
X wrefresh(Msgwin);
X wait_for(' ');
X}
X
X/*
X * wait_for
X * Sit around until the guy types the right key
X */
Xwait_for(ch)
Xregister char ch;
X{
X register char c;
X
X if (ch == '\n')
X while ((c = readchar()) != '\n')
X continue;
X else
X while (readchar() != ch)
X continue;
X}
X
X/*
X * readchar:
X * Reads and returns a character, checking for gross input errors
X */
Xreadchar()
X{
X register int cnt, y, x;
X auto char c;
X
Xover:
X cnt = 0;
X while (read(0, &c, 1) <= 0)
X if (cnt++ > 100) /* if we are getting infinite EOFs */
X bye(); /* quit the game */
X if (c == CTRL(L)) {
X wrefresh(curscr);
X goto over;
X }
X if (c == '\r')
X return '\n';
X else
X return c;
X}
X
X/*
X * getline:
X * Reads the next line up to '\n' or EOF. Multiple spaces are
X * compressed to one space; a space is inserted before a ','
X */
Xchar *
Xgetline()
X{
X register char *sp;
X register int c, oy, ox;
X register WINDOW *oscr;
X
X oscr = stdscr;
X stdscr = Msgwin;
X getyx(stdscr, oy, ox);
X refresh();
X /*
X * loop reading in the string, and put it in a temporary buffer
X */
X for (sp = linebuf; (c = readchar()) != '\n'; clrtoeol(), refresh()) {
X if (c == -1)
X continue;
X else if (c == erasechar()) { /* process erase character */
X if (sp > linebuf) {
X register int i;
X
X sp--;
X for (i = strlen(unctrl(*sp)); i; i--)
X addch('\b');
X }
X continue;
X }
X else if (c == killchar()) { /* process kill character */
X sp = linebuf;
X move(oy, ox);
X continue;
X }
X else if (sp == linebuf && c == ' ')
X continue;
X if (sp >= &linebuf[LINESIZE-1] || !(isprint(c) || c == ' '))
X putchar(CTRL(G));
X else {
X if (islower(c))
X c = toupper(c);
X *sp++ = c;
X addstr(unctrl(c));
X Mpos++;
X }
X }
X *sp = '\0';
X stdscr = oscr;
X return linebuf;
X}
X
X/*
X * bye:
X * Leave the program, cleaning things up as we go.
X */
Xbye()
X{
X signal(SIGINT, SIG_IGN);
X mvcur(0, COLS - 1, LINES - 1, 0);
X fflush(stdout);
X endwin();
X putchar('\n');
X exit(1);
X}
END_OF_io.c
if test 11117 -ne `wc -c score.c <<'END_OF_score.c'
X/*
X * Copyright (c) 1980 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that this notice is preserved and that due credit is given
X * to the University of California at Berkeley. The name of the University
X * may not be used to endorse or promote products derived from this
X * software without specific prior written permission. This software
X * is provided ``as is'' without express or implied warranty.
X */
X
X#ifndef lint
Xstatic char sccsid[] = "@(#)score.c 5.3 (Berkeley) 3/10/88";
X#endif /* not lint */
X
X#include
X#include "deck.h"
X#include "cribbage.h"
X
X
X/*
X * the following arrays give the sum of the scores of the (50 2)*48 = 58800
X * hands obtainable for the crib given the two cards whose ranks index the
X * array. the two arrays are for the case where the suits are equal and
X * not equal respectively
X */
X
Xlong crbescr[ 169 ] = {
X -10000, 271827, 278883, 332319, 347769, 261129, 250653, 253203, 248259,
X 243435, 256275, 237435, 231051, -10000, -10000, 412815, 295707, 349497,
X 267519, 262521, 259695, 254019, 250047, 262887, 244047, 237663, -10000,
X -10000, -10000, 333987, 388629, 262017, 266787, 262971, 252729, 254475,
X 267315, 248475, 242091, -10000, -10000, -10000, -10000, 422097, 302787,
X 256437, 263751, 257883, 254271, 267111, 248271, 241887, -10000, -10000,
X -10000, -10000, -10000, 427677, 387837, 349173, 347985, 423861, 436701,
X 417861, 411477, -10000, -10000, -10000, -10000, -10000, -10000, 336387,
X 298851, 338667, 236487, 249327, 230487, 224103, -10000, -10000, -10000,
X -10000, -10000, -10000, -10000, 408483, 266691, 229803, 246195, 227355,
X 220971, -10000, -10000, -10000, -10000, -10000, -10000, -10000, -10000,
X 300675, 263787, 241695, 226407, 220023, -10000, -10000, -10000, -10000,
X -10000, -10000, -10000, -10000, -10000, 295635, 273543, 219771, 216939,
X -10000, -10000, -10000, -10000, -10000, -10000, -10000, -10000, -10000,
X -10000, 306519, 252747, 211431, -10000, -10000, -10000, -10000, -10000,
X -10000, -10000, -10000, -10000, -10000, -10000, 304287, 262971, -10000,
X -10000, -10000, -10000, -10000, -10000, -10000, -10000, -10000, -10000,
X -10000, -10000, 244131, -10000, -10000, -10000, -10000, -10000, -10000,
X -10000, -10000, -10000, -10000, -10000, -10000, -10000 };
X
Xlong crbnescr[ 169 ] = {
X 325272, 260772, 267828, 321264, 336714, 250074, 239598, 242148, 237204,
X 232380, 246348, 226380, 219996, -10000, 342528, 401760, 284652, 338442,
X 256464, 251466, 248640, 242964, 238992, 252960, 232992, 226608, -10000,
X -10000, 362280, 322932, 377574, 250962, 255732, 251916, 241674, 243420,
X 257388, 237420, 231036, -10000, -10000, -10000, 360768, 411042, 291732,
X 245382, 252696, 246828, 243216, 257184, 237216, 230832, -10000, -10000,
X -10000, -10000, 528768, 416622, 376782, 338118, 336930, 412806, 426774,
X 406806, 400422, -10000, -10000, -10000, -10000, -10000, 369864, 325332,
X 287796, 327612, 225432, 239400, 219432, 213048, -10000, -10000, -10000,
X -10000, -10000, -10000, 359160, 397428, 255636, 218748, 236268, 216300,
X 209916, -10000, -10000, -10000, -10000, -10000, -10000, -10000, 331320,
X 289620, 252732, 231768, 215352, 208968, -10000, -10000, -10000, -10000,
X -10000, -10000, -10000, -10000, 325152, 284580, 263616, 208716, 205884,
X -10000, -10000, -10000, -10000, -10000, -10000, -10000, -10000, -10000,
X 321240, 296592, 241692, 200376, -10000, -10000, -10000, -10000, -10000,
X -10000, -10000, -10000, -10000, -10000, 348600, 294360, 253044, -10000,
X -10000, -10000, -10000, -10000, -10000, -10000, -10000, -10000, -10000,
X -10000, 308664, 233076, -10000, -10000, -10000, -10000, -10000, -10000,
X -10000, -10000, -10000, -10000, -10000, -10000, 295896 };
X
X
Xstatic int ichoose2[ 5 ] = { 0, 0, 2, 6, 12 };
Xstatic int pairpoints, runpoints; /* globals from pairuns */
X
X
X/*
X * scorehand:
X * Score the given hand of n cards and the starter card.
X * n must be <= 4
X */
Xscorehand(hand, starter, n, crb, do_explain)
Xregister CARD hand[];
XCARD starter;
Xint n;
XBOOLEAN crb; /* true if scoring crib */
XBOOLEAN do_explain; /* true if must explain this hand */
X{
X CARD h[(CINHAND + 1)];
X register int i, k;
X register int score;
X register BOOLEAN flag;
X char buf[32];
X
X expl[0] = NULL; /* initialize explanation */
X score = 0;
X flag = TRUE;
X k = hand[0].suit;
X for (i = 0; i < n; i++) { /* check for flush */
X flag = (flag && (hand[i].suit == k));
X if (hand[i].rank == JACK) /* check for his nibs */
X if (hand[i].suit == starter.suit) {
X score++;
X if (do_explain)
X strcat(expl, "His Nobs");
X }
X h[i] = hand[i];
X }
X
X if (flag && n >= CINHAND) {
X if (do_explain && expl[0] != NULL)
X strcat(expl, ", ");
X if (starter.suit == k) {
X score += 5;
X if (do_explain)
X strcat(expl, "Five-flush");
X }
X else if (!crb) {
X score += 4;
X if (do_explain && expl[0] != NULL)
X strcat(expl, ", Four-flush");
X else
X strcpy(expl, "Four-flush");
X }
X }
X
X if (do_explain && expl[0] != NULL)
X strcat(expl, ", ");
X h[n] = starter;
X sorthand(h, n + 1); /* sort by rank */
X i = 2 * fifteens(h, n + 1);
X score += i;
X if (do_explain)
X if (i > 0) {
X (void)sprintf(buf, "%d points in fifteens", i);
X strcat(expl, buf);
X }
X else
X strcat(expl, "No fifteens");
X i = pairuns(h, n + 1);
X score += i;
X if (do_explain)
X if (i > 0) {
X (void)sprintf(buf, ", %d points in pairs, %d in runs",
X pairpoints, runpoints);
X strcat(expl, buf);
X }
X else
X strcat(expl, ", No pairs/runs");
X return score;
X}
X
X/*
X * fifteens:
X * Return number of fifteens in hand of n cards
X */
Xfifteens(hand, n)
Xregister CARD hand[];
Xint n;
X{
X register int *sp, *np;
X register int i;
X register CARD *endp;
X static int sums[15], nsums[15];
X
X np = nsums;
X sp = sums;
X i = 16;
X while (--i) {
X *np++ = 0;
X *sp++ = 0;
X }
X for (endp = &hand[n]; hand < endp; hand++) {
X i = hand->rank + 1;
X if (i > 10)
X i = 10;
X np = &nsums[i];
X np[-1]++; /* one way to make this */
X sp = sums;
X while (i < 15) {
X *np++ += *sp++;
X i++;
X }
X sp = sums;
X np = nsums;
X i = 16;
X while (--i)
X *sp++ = *np++;
X }
X return sums[14];
X}
X
X
X
X/*
X * pairuns returns the number of points in the n card sorted hand
X * due to pairs and runs
X * this routine only works if n is strictly less than 6
X * sets the globals pairpoints and runpoints appropriately
X */
X
Xpairuns( h, n )
X
X CARD h[];
X int n;
X{
X register int i;
X int runlength, runmult, lastmult, curmult;
X int mult1, mult2, pair1, pair2;
X BOOLEAN run;
X
X run = TRUE;
X runlength = 1;
X mult1 = 1;
X pair1 = -1;
X mult2 = 1;
X pair2 = -1;
X curmult = runmult = 1;
X for( i = 1; i < n; i++ ) {
X lastmult = curmult;
X if( h[i].rank == h[i - 1].rank ) {
X if( pair1 < 0 ) {
X pair1 = h[i].rank;
X mult1 = curmult = 2;
X }
X else {
X if( h[i].rank == pair1 ) {
X curmult = ++mult1;
X }
X else {
X if( pair2 < 0 ) {
X pair2 = h[i].rank;
X mult2 = curmult = 2;
X }
X else {
X curmult = ++mult2;
X }
X }
X }
X if( i == (n - 1) && run ) {
X runmult *= curmult;
X }
X }
X else {
X curmult = 1;
X if( h[i].rank == h[i - 1].rank + 1 ) {
X if( run ) {
X ++runlength;
X }
X else {
X if( runlength < 3 ) { /* only if old short */
X run = TRUE;
X runlength = 2;
X runmult = 1;
X }
X }
X runmult *= lastmult;
X }
X else {
X if( run ) runmult *= lastmult; /* if just ended */
X run = FALSE;
X }
X }
X }
X pairpoints = ichoose2[ mult1 ] + ichoose2[ mult2 ];
X runpoints = ( runlength >= 3 ? runlength*runmult : 0 );
X return( pairpoints + runpoints );
X}
X
X
X
X/*
X * pegscore tells how many points crd would get if played after
X * the n cards in tbl during pegging
X */
X
Xpegscore( crd, tbl, n, sum )
X
X CARD crd, tbl[];
X int n;
X int sum;
X{
X BOOLEAN got[ RANKS ];
X register int i, j, scr;
X int k, lo, hi;
X
X sum += VAL( crd.rank );
X if( sum > 31 ) return( -1 );
X if( sum == 31 || sum == 15 ) scr = 2;
X else scr = 0;
X if( !n ) return( scr );
X j = 1;
X while( ( crd.rank == tbl[n - j].rank ) && ( n - j >= 0 ) ) ++j;
X if( j > 1 ) return( scr + ichoose2[j] );
X if( n < 2 ) return( scr );
X lo = hi = crd.rank;
X for( i = 0; i < RANKS; i++ ) got[i] = FALSE;
X got[ crd.rank ] = TRUE;
X k = -1;
X for( i = n - 1; i >= 0; --i ) {
X if( got[ tbl[i].rank ] ) break;
X got[ tbl[i].rank ] = TRUE;
X if( tbl[i].rank < lo ) lo = tbl[i].rank;
X if( tbl[i].rank > hi ) hi = tbl[i].rank;
X for( j = lo; j <= hi; j++ ) if( !got[j] ) break;
X if( j > hi ) k = hi - lo + 1;
X }
X if( k >= 3 ) return( scr + k );
X else return( scr );
X}
X
X
X
X/*
X * adjust takes a two card hand that will be put in the crib
X * and returns an adjusted normalized score for the number of
X * points such a crib will get.
X */
X
Xadjust( cb, tnv )
X
X CARD cb[], tnv;
X{
X int i, c0, c1;
X long scr;
X
X c0 = cb[0].rank;
X c1 = cb[1].rank;
X if( c0 > c1 ) {
X i = c0;
X c0 = c1;
X c1 = i;
X }
X if( cb[0].suit != cb[1].suit ) scr = crbnescr[ RANKS*c0 + c1 ];
X else scr = crbescr[ RANKS*c0 + c1 ];
X if( scr <= 0 ) {
X printf( "\nADJUST: internal error %d %d\n", c0, c1 );
X exit( 93 );
X }
X return( (scr + 29400)/58800 );
X}
X
X
X
END_OF_score.c
if test 9414 -ne `wc -c