xref: /csrg-svn/games/cribbage/support.c (revision 60777)
159264Sbostic /*-
2*60777Sbostic  * Copyright (c) 1980, 1993
3*60777Sbostic  *	The Regents of the University of California.  All rights reserved.
433707Sbostic  *
542577Sbostic  * %sccs.include.redist.c%
621507Smckusick  */
712573Sarnold 
821507Smckusick #ifndef lint
9*60777Sbostic static char sccsid[] = "@(#)support.c	8.1 (Berkeley) 05/31/93";
1033707Sbostic #endif /* not lint */
1121507Smckusick 
1259264Sbostic #include <curses.h>
1359264Sbostic #include <string.h>
147711Sarnold 
1559264Sbostic #include "deck.h"
1659264Sbostic #include "cribbage.h"
1759264Sbostic #include "cribcur.h"
187711Sarnold 
1959264Sbostic #define	NTV	10		/* number scores to test */
207711Sarnold 
217711Sarnold /* score to test reachability of, and order to test them in */
2259264Sbostic int tv[NTV] = {8, 7, 9, 6, 11, 12, 13, 14, 10, 5};
237711Sarnold 
247711Sarnold /*
257711Sarnold  * computer chooses what to play in pegging...
267711Sarnold  * only called if no playable card will score points
277711Sarnold  */
2859264Sbostic int
cchose(h,n,s)2959264Sbostic cchose(h, n, s)
3059264Sbostic 	CARD h[];
3159264Sbostic 	int n, s;
327711Sarnold {
3359264Sbostic 	register int i, j, l;
347711Sarnold 
3559264Sbostic 	if (n <= 1)
3659264Sbostic 		return (0);
3759264Sbostic 	if (s < 4) {		/* try for good value */
3859264Sbostic 		if ((j = anysumto(h, n, s, 4)) >= 0)
3959264Sbostic 			return (j);
4059264Sbostic 		if ((j = anysumto(h, n, s, 3)) >= 0 && s == 0)
4159264Sbostic 			return (j);
427711Sarnold 	}
4359264Sbostic 	if (s > 0 && s < 20) {
4459264Sbostic 				/* try for retaliation to 31 */
4559264Sbostic 		for (i = 1; i <= 10; i++) {
4659264Sbostic 			if ((j = anysumto(h, n, s, 21 - i)) >= 0) {
4759264Sbostic 				if ((l = numofval(h, n, i)) > 0) {
4859264Sbostic 					if (l > 1 || VAL(h[j].rank) != i)
4959264Sbostic 						return (j);
5059264Sbostic 				}
5159264Sbostic 			}
527711Sarnold 		}
537711Sarnold 	}
5459264Sbostic 	if (s < 15) {
5559264Sbostic 				/* for retaliation after 15 */
5659264Sbostic 		for (i = 0; i < NTV; i++) {
5759264Sbostic 			if ((j = anysumto(h, n, s, tv[i])) >= 0) {
5859264Sbostic 				if ((l = numofval(h, n, 15 - tv[i])) > 0) {
5959264Sbostic 					if (l > 1 ||
6059264Sbostic 					    VAL(h[j].rank) != 15 - tv[i])
6159264Sbostic 						return (j);
6259264Sbostic 				}
6359264Sbostic 			}
647711Sarnold 		}
657711Sarnold 	}
667711Sarnold 	j = -1;
6759264Sbostic 				/* remember: h is sorted */
6859264Sbostic 	for (i = n - 1; i >= 0; --i) {
6959264Sbostic 		l = s + VAL(h[i].rank);
7059264Sbostic 		if (l > 31)
7159264Sbostic 			continue;
7259264Sbostic 		if (l != 5 && l != 10 && l != 21) {
7359264Sbostic 			j = i;
7459264Sbostic 			break;
7559264Sbostic 		}
767711Sarnold 	}
7759264Sbostic 	if (j >= 0)
7859264Sbostic 		return (j);
7959264Sbostic 	for (i = n - 1; i >= 0; --i) {
8059264Sbostic 		l = s + VAL(h[i].rank);
8159264Sbostic 		if (l > 31)
8259264Sbostic 			continue;
8359264Sbostic 		if (j < 0)
8459264Sbostic 			j = i;
8559264Sbostic 		if (l != 5 && l != 21) {
8659264Sbostic 			j = i;
8759264Sbostic 			break;
8859264Sbostic 		}
897711Sarnold 	}
9059264Sbostic 	return (j);
917711Sarnold }
927711Sarnold 
937711Sarnold /*
947873Sarnold  * plyrhand:
957873Sarnold  *	Evaluate and score a player hand or crib
967711Sarnold  */
9759264Sbostic int
plyrhand(hand,s)987873Sarnold plyrhand(hand, s)
9959264Sbostic 	CARD    hand[];
10059264Sbostic 	char   *s;
1017711Sarnold {
10259264Sbostic 	static char prompt[BUFSIZ];
10359264Sbostic 	register int i, j;
10459264Sbostic 	register BOOLEAN win;
1057711Sarnold 
10659264Sbostic 	prhand(hand, CINHAND, Playwin, FALSE);
10759264Sbostic 	(void) sprintf(prompt, "Your %s scores ", s);
10859264Sbostic 	i = scorehand(hand, turnover, CINHAND, strcmp(s, "crib") == 0, explain);
10959264Sbostic 	if ((j = number(0, 29, prompt)) == 19)
11059264Sbostic 		j = 0;
11159264Sbostic 	if (i != j) {
11259264Sbostic 		if (i < j) {
11359264Sbostic 			win = chkscr(&pscore, i);
11459264Sbostic 			msg("It's really only %d points; I get %d", i, 2);
11559264Sbostic 			if (!win)
11659264Sbostic 				win = chkscr(&cscore, 2);
11759264Sbostic 		} else {
11859264Sbostic 			win = chkscr(&pscore, j);
11959264Sbostic 			msg("You should have taken %d, not %d!", i, j);
12059264Sbostic 		}
12159264Sbostic 		if (explain)
12259264Sbostic 			msg("Explanation: %s", expl);
12359264Sbostic 		do_wait();
12459264Sbostic 	} else
12559264Sbostic 		win = chkscr(&pscore, i);
12659264Sbostic 	return (win);
1277711Sarnold }
1287711Sarnold 
1297873Sarnold /*
1307873Sarnold  * comphand:
1317873Sarnold  *	Handle scoring and displaying the computers hand
1327873Sarnold  */
13359264Sbostic int
comphand(h,s)1347873Sarnold comphand(h, s)
13559264Sbostic 	CARD h[];
13659264Sbostic 	char *s;
1377873Sarnold {
13859264Sbostic 	register int j;
1397711Sarnold 
14014910Sarnold 	j = scorehand(h, turnover, CINHAND, strcmp(s, "crib") == 0, FALSE);
1418074Sarnold 	prhand(h, CINHAND, Compwin, FALSE);
1427873Sarnold 	msg("My %s scores %d", s, (j == 0 ? 19 : j));
14359264Sbostic 	return (chkscr(&cscore, j));
1447873Sarnold }
1457711Sarnold 
1467711Sarnold /*
1477873Sarnold  * chkscr:
1487873Sarnold  *	Add inc to scr and test for > glimit, printing on the scoring
1497873Sarnold  *	board while we're at it.
1507711Sarnold  */
15159264Sbostic int Lastscore[2] = {-1, -1};
1527711Sarnold 
15359264Sbostic int
chkscr(scr,inc)1547873Sarnold chkscr(scr, inc)
15559264Sbostic 	int    *scr, inc;
1567711Sarnold {
15759264Sbostic 	BOOLEAN myturn;
1587711Sarnold 
1597873Sarnold 	myturn = (scr == &cscore);
1607873Sarnold 	if (inc != 0) {
1617873Sarnold 		prpeg(Lastscore[myturn], '.', myturn);
1627873Sarnold 		Lastscore[myturn] = *scr;
1637938Sarnold 		*scr += inc;
1647938Sarnold 		prpeg(*scr, PEG, myturn);
1658136Sarnold 		refresh();
1667873Sarnold 	}
1677936Sarnold 	return (*scr >= glimit);
1687711Sarnold }
1697711Sarnold 
1707711Sarnold /*
1717873Sarnold  * prpeg:
17211398Sarnold  *	Put out the peg character on the score board and put the
17311398Sarnold  *	score up on the board.
1747711Sarnold  */
17559264Sbostic void
prpeg(score,peg,myturn)1767873Sarnold prpeg(score, peg, myturn)
17759264Sbostic 	register int score;
17859264Sbostic 	int peg;
17959264Sbostic 	BOOLEAN myturn;
1807873Sarnold {
18159264Sbostic 	register int y, x;
1827711Sarnold 
1837873Sarnold 	if (!myturn)
1847873Sarnold 		y = SCORE_Y + 2;
1857873Sarnold 	else
1867873Sarnold 		y = SCORE_Y + 5;
1877938Sarnold 
1887938Sarnold 	if (score <= 0 || score >= glimit) {
1897938Sarnold 		if (peg == '.')
1907938Sarnold 			peg = ' ';
1917938Sarnold 		if (score == 0)
1927938Sarnold 			x = SCORE_X + 2;
1937938Sarnold 		else {
1947938Sarnold 			x = SCORE_X + 2;
1957938Sarnold 			y++;
1967938Sarnold 		}
19759264Sbostic 	} else {
1987938Sarnold 		x = (score - 1) % 30;
1997938Sarnold 		if (score > 90 || (score > 30 && score <= 60)) {
2007938Sarnold 			y++;
2017938Sarnold 			x = 29 - x;
2027938Sarnold 		}
2037938Sarnold 		x += x / 5;
2047938Sarnold 		x += SCORE_X + 3;
2057938Sarnold 	}
2067873Sarnold 	mvaddch(y, x, peg);
20711398Sarnold 	mvprintw(SCORE_Y + (myturn ? 7 : 1), SCORE_X + 10, "%3d", score);
2087711Sarnold }
2097711Sarnold 
2107711Sarnold /*
2117711Sarnold  * cdiscard -- the computer figures out what is the best discard for
2127711Sarnold  * the crib and puts the best two cards at the end
2137711Sarnold  */
21459264Sbostic void
cdiscard(mycrib)21559264Sbostic cdiscard(mycrib)
21659264Sbostic 	BOOLEAN mycrib;
2177711Sarnold {
21859264Sbostic 	CARD    d[CARDS], h[FULLHAND], cb[2];
21959264Sbostic 	register int i, j, k;
22059264Sbostic 	int     nc, ns;
22159264Sbostic 	long    sums[15];
22259264Sbostic 	static int undo1[15] = {0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 3, 3, 4};
22359264Sbostic 	static int undo2[15] = {1, 2, 3, 4, 5, 2, 3, 4, 5, 3, 4, 5, 4, 5, 5};
2247711Sarnold 
22559264Sbostic 	makedeck(d);
2267711Sarnold 	nc = CARDS;
22759264Sbostic 	for (i = 0; i < knownum; i++) {	/* get all other cards */
22859264Sbostic 		cremove(known[i], d, nc--);
2297711Sarnold 	}
23059264Sbostic 	for (i = 0; i < 15; i++)
23159264Sbostic 		sums[i] = 0L;
2327711Sarnold 	ns = 0;
23359264Sbostic 	for (i = 0; i < (FULLHAND - 1); i++) {
23459264Sbostic 		cb[0] = chand[i];
23559264Sbostic 		for (j = i + 1; j < FULLHAND; j++) {
23659264Sbostic 			cb[1] = chand[j];
23759264Sbostic 			for (k = 0; k < FULLHAND; k++)
23859264Sbostic 				h[k] = chand[k];
23959264Sbostic 			cremove(chand[i], h, FULLHAND);
24059264Sbostic 			cremove(chand[j], h, FULLHAND - 1);
24159264Sbostic 			for (k = 0; k < nc; k++) {
24259264Sbostic 				sums[ns] +=
24359264Sbostic 				    scorehand(h, d[k], CINHAND, TRUE, FALSE);
24459264Sbostic 				if (mycrib)
24559264Sbostic 					sums[ns] += adjust(cb, d[k]);
24659264Sbostic 				else
24759264Sbostic 					sums[ns] -= adjust(cb, d[k]);
24859264Sbostic 			}
24959264Sbostic 			++ns;
2507711Sarnold 		}
2517711Sarnold 	}
2527711Sarnold 	j = 0;
25359264Sbostic 	for (i = 1; i < 15; i++)
25459264Sbostic 		if (sums[i] > sums[j])
25559264Sbostic 			j = i;
25659264Sbostic 	for (k = 0; k < FULLHAND; k++)
25759264Sbostic 		h[k] = chand[k];
25859264Sbostic 	cremove(h[undo1[j]], chand, FULLHAND);
25959264Sbostic 	cremove(h[undo2[j]], chand, FULLHAND - 1);
26059264Sbostic 	chand[4] = h[undo1[j]];
26159264Sbostic 	chand[5] = h[undo2[j]];
2627711Sarnold }
2637711Sarnold 
2647711Sarnold /*
2657711Sarnold  * returns true if some card in hand can be played without exceeding 31
2667711Sarnold  */
26759264Sbostic int
anymove(hand,n,sum)26859264Sbostic anymove(hand, n, sum)
26959264Sbostic 	CARD hand[];
27059264Sbostic 	int n, sum;
2717711Sarnold {
27259264Sbostic 	register int i, j;
2737711Sarnold 
27459264Sbostic 	if (n < 1)
27559264Sbostic 		return (FALSE);
2767711Sarnold 	j = hand[0].rank;
27759264Sbostic 	for (i = 1; i < n; i++) {
27859264Sbostic 		if (hand[i].rank < j)
27959264Sbostic 			j = hand[i].rank;
2807711Sarnold 	}
28159264Sbostic 	return (sum + VAL(j) <= 31);
2827711Sarnold }
2837711Sarnold 
2847711Sarnold /*
2857711Sarnold  * anysumto returns the index (0 <= i < n) of the card in hand that brings
2867711Sarnold  * the s up to t, or -1 if there is none
2877711Sarnold  */
28859264Sbostic int
anysumto(hand,n,s,t)28959264Sbostic anysumto(hand, n, s, t)
29059264Sbostic 	CARD hand[];
29159264Sbostic 	int n, s, t;
2927711Sarnold {
29359264Sbostic 	register int i;
2947711Sarnold 
29559264Sbostic 	for (i = 0; i < n; i++) {
29659264Sbostic 		if (s + VAL(hand[i].rank) == t)
29759264Sbostic 			return (i);
2987711Sarnold 	}
29959264Sbostic 	return (-1);
3007711Sarnold }
3017711Sarnold 
3027711Sarnold /*
3037711Sarnold  * return the number of cards in h having the given rank value
3047711Sarnold  */
30559264Sbostic int
numofval(h,n,v)30659264Sbostic numofval(h, n, v)
30759264Sbostic 	CARD h[];
30859264Sbostic 	int n, v;
3097711Sarnold {
31059264Sbostic 	register int i, j;
3117711Sarnold 
3127711Sarnold 	j = 0;
31359264Sbostic 	for (i = 0; i < n; i++) {
31459264Sbostic 		if (VAL(h[i].rank) == v)
31559264Sbostic 			++j;
3167711Sarnold 	}
31759264Sbostic 	return (j);
3187711Sarnold }
3197711Sarnold 
3207711Sarnold /*
3217711Sarnold  * makeknown remembers all n cards in h for future recall
3227711Sarnold  */
32359264Sbostic void
makeknown(h,n)32459264Sbostic makeknown(h, n)
32559264Sbostic 	CARD h[];
32659264Sbostic 	int n;
3277711Sarnold {
32859264Sbostic 	register int i;
3297711Sarnold 
33059264Sbostic 	for (i = 0; i < n; i++)
33159264Sbostic 		known[knownum++] = h[i];
3327711Sarnold }
333