xref: /original-bsd/games/cribbage/support.c (revision e5906f05)
1 /*-
2  * Copyright (c) 1980, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 static char sccsid[] = "@(#)support.c	8.1 (Berkeley) 05/31/93";
10 #endif /* not lint */
11 
12 #include <curses.h>
13 #include <string.h>
14 
15 #include "deck.h"
16 #include "cribbage.h"
17 #include "cribcur.h"
18 
19 #define	NTV	10		/* number scores to test */
20 
21 /* score to test reachability of, and order to test them in */
22 int tv[NTV] = {8, 7, 9, 6, 11, 12, 13, 14, 10, 5};
23 
24 /*
25  * computer chooses what to play in pegging...
26  * only called if no playable card will score points
27  */
28 int
29 cchose(h, n, s)
30 	CARD h[];
31 	int n, s;
32 {
33 	register int i, j, l;
34 
35 	if (n <= 1)
36 		return (0);
37 	if (s < 4) {		/* try for good value */
38 		if ((j = anysumto(h, n, s, 4)) >= 0)
39 			return (j);
40 		if ((j = anysumto(h, n, s, 3)) >= 0 && s == 0)
41 			return (j);
42 	}
43 	if (s > 0 && s < 20) {
44 				/* try for retaliation to 31 */
45 		for (i = 1; i <= 10; i++) {
46 			if ((j = anysumto(h, n, s, 21 - i)) >= 0) {
47 				if ((l = numofval(h, n, i)) > 0) {
48 					if (l > 1 || VAL(h[j].rank) != i)
49 						return (j);
50 				}
51 			}
52 		}
53 	}
54 	if (s < 15) {
55 				/* for retaliation after 15 */
56 		for (i = 0; i < NTV; i++) {
57 			if ((j = anysumto(h, n, s, tv[i])) >= 0) {
58 				if ((l = numofval(h, n, 15 - tv[i])) > 0) {
59 					if (l > 1 ||
60 					    VAL(h[j].rank) != 15 - tv[i])
61 						return (j);
62 				}
63 			}
64 		}
65 	}
66 	j = -1;
67 				/* remember: h is sorted */
68 	for (i = n - 1; i >= 0; --i) {
69 		l = s + VAL(h[i].rank);
70 		if (l > 31)
71 			continue;
72 		if (l != 5 && l != 10 && l != 21) {
73 			j = i;
74 			break;
75 		}
76 	}
77 	if (j >= 0)
78 		return (j);
79 	for (i = n - 1; i >= 0; --i) {
80 		l = s + VAL(h[i].rank);
81 		if (l > 31)
82 			continue;
83 		if (j < 0)
84 			j = i;
85 		if (l != 5 && l != 21) {
86 			j = i;
87 			break;
88 		}
89 	}
90 	return (j);
91 }
92 
93 /*
94  * plyrhand:
95  *	Evaluate and score a player hand or crib
96  */
97 int
98 plyrhand(hand, s)
99 	CARD    hand[];
100 	char   *s;
101 {
102 	static char prompt[BUFSIZ];
103 	register int i, j;
104 	register BOOLEAN win;
105 
106 	prhand(hand, CINHAND, Playwin, FALSE);
107 	(void) sprintf(prompt, "Your %s scores ", s);
108 	i = scorehand(hand, turnover, CINHAND, strcmp(s, "crib") == 0, explain);
109 	if ((j = number(0, 29, prompt)) == 19)
110 		j = 0;
111 	if (i != j) {
112 		if (i < j) {
113 			win = chkscr(&pscore, i);
114 			msg("It's really only %d points; I get %d", i, 2);
115 			if (!win)
116 				win = chkscr(&cscore, 2);
117 		} else {
118 			win = chkscr(&pscore, j);
119 			msg("You should have taken %d, not %d!", i, j);
120 		}
121 		if (explain)
122 			msg("Explanation: %s", expl);
123 		do_wait();
124 	} else
125 		win = chkscr(&pscore, i);
126 	return (win);
127 }
128 
129 /*
130  * comphand:
131  *	Handle scoring and displaying the computers hand
132  */
133 int
134 comphand(h, s)
135 	CARD h[];
136 	char *s;
137 {
138 	register int j;
139 
140 	j = scorehand(h, turnover, CINHAND, strcmp(s, "crib") == 0, FALSE);
141 	prhand(h, CINHAND, Compwin, FALSE);
142 	msg("My %s scores %d", s, (j == 0 ? 19 : j));
143 	return (chkscr(&cscore, j));
144 }
145 
146 /*
147  * chkscr:
148  *	Add inc to scr and test for > glimit, printing on the scoring
149  *	board while we're at it.
150  */
151 int Lastscore[2] = {-1, -1};
152 
153 int
154 chkscr(scr, inc)
155 	int    *scr, inc;
156 {
157 	BOOLEAN myturn;
158 
159 	myturn = (scr == &cscore);
160 	if (inc != 0) {
161 		prpeg(Lastscore[myturn], '.', myturn);
162 		Lastscore[myturn] = *scr;
163 		*scr += inc;
164 		prpeg(*scr, PEG, myturn);
165 		refresh();
166 	}
167 	return (*scr >= glimit);
168 }
169 
170 /*
171  * prpeg:
172  *	Put out the peg character on the score board and put the
173  *	score up on the board.
174  */
175 void
176 prpeg(score, peg, myturn)
177 	register int score;
178 	int peg;
179 	BOOLEAN myturn;
180 {
181 	register int y, x;
182 
183 	if (!myturn)
184 		y = SCORE_Y + 2;
185 	else
186 		y = SCORE_Y + 5;
187 
188 	if (score <= 0 || score >= glimit) {
189 		if (peg == '.')
190 			peg = ' ';
191 		if (score == 0)
192 			x = SCORE_X + 2;
193 		else {
194 			x = SCORE_X + 2;
195 			y++;
196 		}
197 	} else {
198 		x = (score - 1) % 30;
199 		if (score > 90 || (score > 30 && score <= 60)) {
200 			y++;
201 			x = 29 - x;
202 		}
203 		x += x / 5;
204 		x += SCORE_X + 3;
205 	}
206 	mvaddch(y, x, peg);
207 	mvprintw(SCORE_Y + (myturn ? 7 : 1), SCORE_X + 10, "%3d", score);
208 }
209 
210 /*
211  * cdiscard -- the computer figures out what is the best discard for
212  * the crib and puts the best two cards at the end
213  */
214 void
215 cdiscard(mycrib)
216 	BOOLEAN mycrib;
217 {
218 	CARD    d[CARDS], h[FULLHAND], cb[2];
219 	register int i, j, k;
220 	int     nc, ns;
221 	long    sums[15];
222 	static int undo1[15] = {0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 3, 3, 4};
223 	static int undo2[15] = {1, 2, 3, 4, 5, 2, 3, 4, 5, 3, 4, 5, 4, 5, 5};
224 
225 	makedeck(d);
226 	nc = CARDS;
227 	for (i = 0; i < knownum; i++) {	/* get all other cards */
228 		cremove(known[i], d, nc--);
229 	}
230 	for (i = 0; i < 15; i++)
231 		sums[i] = 0L;
232 	ns = 0;
233 	for (i = 0; i < (FULLHAND - 1); i++) {
234 		cb[0] = chand[i];
235 		for (j = i + 1; j < FULLHAND; j++) {
236 			cb[1] = chand[j];
237 			for (k = 0; k < FULLHAND; k++)
238 				h[k] = chand[k];
239 			cremove(chand[i], h, FULLHAND);
240 			cremove(chand[j], h, FULLHAND - 1);
241 			for (k = 0; k < nc; k++) {
242 				sums[ns] +=
243 				    scorehand(h, d[k], CINHAND, TRUE, FALSE);
244 				if (mycrib)
245 					sums[ns] += adjust(cb, d[k]);
246 				else
247 					sums[ns] -= adjust(cb, d[k]);
248 			}
249 			++ns;
250 		}
251 	}
252 	j = 0;
253 	for (i = 1; i < 15; i++)
254 		if (sums[i] > sums[j])
255 			j = i;
256 	for (k = 0; k < FULLHAND; k++)
257 		h[k] = chand[k];
258 	cremove(h[undo1[j]], chand, FULLHAND);
259 	cremove(h[undo2[j]], chand, FULLHAND - 1);
260 	chand[4] = h[undo1[j]];
261 	chand[5] = h[undo2[j]];
262 }
263 
264 /*
265  * returns true if some card in hand can be played without exceeding 31
266  */
267 int
268 anymove(hand, n, sum)
269 	CARD hand[];
270 	int n, sum;
271 {
272 	register int i, j;
273 
274 	if (n < 1)
275 		return (FALSE);
276 	j = hand[0].rank;
277 	for (i = 1; i < n; i++) {
278 		if (hand[i].rank < j)
279 			j = hand[i].rank;
280 	}
281 	return (sum + VAL(j) <= 31);
282 }
283 
284 /*
285  * anysumto returns the index (0 <= i < n) of the card in hand that brings
286  * the s up to t, or -1 if there is none
287  */
288 int
289 anysumto(hand, n, s, t)
290 	CARD hand[];
291 	int n, s, t;
292 {
293 	register int i;
294 
295 	for (i = 0; i < n; i++) {
296 		if (s + VAL(hand[i].rank) == t)
297 			return (i);
298 	}
299 	return (-1);
300 }
301 
302 /*
303  * return the number of cards in h having the given rank value
304  */
305 int
306 numofval(h, n, v)
307 	CARD h[];
308 	int n, v;
309 {
310 	register int i, j;
311 
312 	j = 0;
313 	for (i = 0; i < n; i++) {
314 		if (VAL(h[i].rank) == v)
315 			++j;
316 	}
317 	return (j);
318 }
319 
320 /*
321  * makeknown remembers all n cards in h for future recall
322  */
323 void
324 makeknown(h, n)
325 	CARD h[];
326 	int n;
327 {
328 	register int i;
329 
330 	for (i = 0; i < n; i++)
331 		known[knownum++] = h[i];
332 }
333