xref: /netbsd-src/games/cribbage/support.c (revision de1dfb1250df962f1ff3a011772cf58e605aed11)
1 /*	$NetBSD: support.c,v 1.7 2003/08/07 09:37:11 agc Exp $	*/
2 
3 /*-
4  * Copyright (c) 1980, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 #ifndef lint
34 #if 0
35 static char sccsid[] = "@(#)support.c	8.1 (Berkeley) 5/31/93";
36 #else
37 __RCSID("$NetBSD: support.c,v 1.7 2003/08/07 09:37:11 agc Exp $");
38 #endif
39 #endif /* not lint */
40 
41 #include <curses.h>
42 #include <string.h>
43 
44 #include "deck.h"
45 #include "cribbage.h"
46 #include "cribcur.h"
47 
48 #define	NTV	10		/* number scores to test */
49 
50 /* score to test reachability of, and order to test them in */
51 const int tv[NTV] = {8, 7, 9, 6, 11, 12, 13, 14, 10, 5};
52 
53 /*
54  * computer chooses what to play in pegging...
55  * only called if no playable card will score points
56  */
57 int
58 cchose(h, n, s)
59 	const CARD h[];
60 	int n, s;
61 {
62 	int i, j, l;
63 
64 	if (n <= 1)
65 		return (0);
66 	if (s < 4) {		/* try for good value */
67 		if ((j = anysumto(h, n, s, 4)) >= 0)
68 			return (j);
69 		if ((j = anysumto(h, n, s, 3)) >= 0 && s == 0)
70 			return (j);
71 	}
72 	if (s > 0 && s < 20) {
73 				/* try for retaliation to 31 */
74 		for (i = 1; i <= 10; i++) {
75 			if ((j = anysumto(h, n, s, 21 - i)) >= 0) {
76 				if ((l = numofval(h, n, i)) > 0) {
77 					if (l > 1 || VAL(h[j].rank) != i)
78 						return (j);
79 				}
80 			}
81 		}
82 	}
83 	if (s < 15) {
84 				/* for retaliation after 15 */
85 		for (i = 0; i < NTV; i++) {
86 			if ((j = anysumto(h, n, s, tv[i])) >= 0) {
87 				if ((l = numofval(h, n, 15 - tv[i])) > 0) {
88 					if (l > 1 ||
89 					    VAL(h[j].rank) != 15 - tv[i])
90 						return (j);
91 				}
92 			}
93 		}
94 	}
95 	j = -1;
96 				/* remember: h is sorted */
97 	for (i = n - 1; i >= 0; --i) {
98 		l = s + VAL(h[i].rank);
99 		if (l > 31)
100 			continue;
101 		if (l != 5 && l != 10 && l != 21) {
102 			j = i;
103 			break;
104 		}
105 	}
106 	if (j >= 0)
107 		return (j);
108 	for (i = n - 1; i >= 0; --i) {
109 		l = s + VAL(h[i].rank);
110 		if (l > 31)
111 			continue;
112 		if (j < 0)
113 			j = i;
114 		if (l != 5 && l != 21) {
115 			j = i;
116 			break;
117 		}
118 	}
119 	return (j);
120 }
121 
122 /*
123  * plyrhand:
124  *	Evaluate and score a player hand or crib
125  */
126 int
127 plyrhand(hand, s)
128 	const CARD    hand[];
129 	const char   *s;
130 {
131 	static char prompt[BUFSIZ];
132 	int i, j;
133 	BOOLEAN win;
134 
135 	prhand(hand, CINHAND, Playwin, FALSE);
136 	(void) sprintf(prompt, "Your %s scores ", s);
137 	i = scorehand(hand, turnover, CINHAND, strcmp(s, "crib") == 0, explain);
138 	if ((j = number(0, 29, prompt)) == 19)
139 		j = 0;
140 	if (i != j) {
141 		if (i < j) {
142 			win = chkscr(&pscore, i);
143 			msg("It's really only %d points; I get %d", i, 2);
144 			if (!win)
145 				win = chkscr(&cscore, 2);
146 		} else {
147 			win = chkscr(&pscore, j);
148 			msg("You should have taken %d, not %d!", i, j);
149 		}
150 		if (explain)
151 			msg("Explanation: %s", explan);
152 		do_wait();
153 	} else
154 		win = chkscr(&pscore, i);
155 	return (win);
156 }
157 
158 /*
159  * comphand:
160  *	Handle scoring and displaying the computers hand
161  */
162 int
163 comphand(h, s)
164 	const CARD h[];
165 	const char *s;
166 {
167 	int j;
168 
169 	j = scorehand(h, turnover, CINHAND, strcmp(s, "crib") == 0, FALSE);
170 	prhand(h, CINHAND, Compwin, FALSE);
171 	msg("My %s scores %d", s, (j == 0 ? 19 : j));
172 	return (chkscr(&cscore, j));
173 }
174 
175 /*
176  * chkscr:
177  *	Add inc to scr and test for > glimit, printing on the scoring
178  *	board while we're at it.
179  */
180 int Lastscore[2] = {-1, -1};
181 
182 int
183 chkscr(scr, inc)
184 	int    *scr, inc;
185 {
186 	BOOLEAN myturn;
187 
188 	myturn = (scr == &cscore);
189 	if (inc != 0) {
190 		prpeg(Lastscore[(int)myturn], '.', myturn);
191 		Lastscore[(int)myturn] = *scr;
192 		*scr += inc;
193 		prpeg(*scr, PEG, myturn);
194 		refresh();
195 	}
196 	return (*scr >= glimit);
197 }
198 
199 /*
200  * prpeg:
201  *	Put out the peg character on the score board and put the
202  *	score up on the board.
203  */
204 void
205 prpeg(score, peg, myturn)
206 	int score;
207 	int peg;
208 	BOOLEAN myturn;
209 {
210 	int y, x;
211 
212 	if (!myturn)
213 		y = SCORE_Y + 2;
214 	else
215 		y = SCORE_Y + 5;
216 
217 	if (score <= 0 || score >= glimit) {
218 		if (peg == '.')
219 			peg = ' ';
220 		if (score == 0)
221 			x = SCORE_X + 2;
222 		else {
223 			x = SCORE_X + 2;
224 			y++;
225 		}
226 	} else {
227 		x = (score - 1) % 30;
228 		if (score > 90 || (score > 30 && score <= 60)) {
229 			y++;
230 			x = 29 - x;
231 		}
232 		x += x / 5;
233 		x += SCORE_X + 3;
234 	}
235 	mvaddch(y, x, peg);
236 	mvprintw(SCORE_Y + (myturn ? 7 : 1), SCORE_X + 10, "%3d", score);
237 }
238 
239 /*
240  * cdiscard -- the computer figures out what is the best discard for
241  * the crib and puts the best two cards at the end
242  */
243 void
244 cdiscard(mycrib)
245 	BOOLEAN mycrib;
246 {
247 	CARD    d[CARDS], h[FULLHAND], cb[2];
248 	int i, j, k;
249 	int     nc, ns;
250 	long    sums[15];
251 	static int undo1[15] = {0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 3, 3, 4};
252 	static int undo2[15] = {1, 2, 3, 4, 5, 2, 3, 4, 5, 3, 4, 5, 4, 5, 5};
253 
254 	makedeck(d);
255 	nc = CARDS;
256 	for (i = 0; i < knownum; i++) {	/* get all other cards */
257 		cremove(known[i], d, nc--);
258 	}
259 	for (i = 0; i < 15; i++)
260 		sums[i] = 0L;
261 	ns = 0;
262 	for (i = 0; i < (FULLHAND - 1); i++) {
263 		cb[0] = chand[i];
264 		for (j = i + 1; j < FULLHAND; j++) {
265 			cb[1] = chand[j];
266 			for (k = 0; k < FULLHAND; k++)
267 				h[k] = chand[k];
268 			cremove(chand[i], h, FULLHAND);
269 			cremove(chand[j], h, FULLHAND - 1);
270 			for (k = 0; k < nc; k++) {
271 				sums[ns] +=
272 				    scorehand(h, d[k], CINHAND, TRUE, FALSE);
273 				if (mycrib)
274 					sums[ns] += adjust(cb, d[k]);
275 				else
276 					sums[ns] -= adjust(cb, d[k]);
277 			}
278 			++ns;
279 		}
280 	}
281 	j = 0;
282 	for (i = 1; i < 15; i++)
283 		if (sums[i] > sums[j])
284 			j = i;
285 	for (k = 0; k < FULLHAND; k++)
286 		h[k] = chand[k];
287 	cremove(h[undo1[j]], chand, FULLHAND);
288 	cremove(h[undo2[j]], chand, FULLHAND - 1);
289 	chand[4] = h[undo1[j]];
290 	chand[5] = h[undo2[j]];
291 }
292 
293 /*
294  * returns true if some card in hand can be played without exceeding 31
295  */
296 int
297 anymove(hand, n, sum)
298 	const CARD hand[];
299 	int n, sum;
300 {
301 	int i, j;
302 
303 	if (n < 1)
304 		return (FALSE);
305 	j = hand[0].rank;
306 	for (i = 1; i < n; i++) {
307 		if (hand[i].rank < j)
308 			j = hand[i].rank;
309 	}
310 	return (sum + VAL(j) <= 31);
311 }
312 
313 /*
314  * anysumto returns the index (0 <= i < n) of the card in hand that brings
315  * the s up to t, or -1 if there is none
316  */
317 int
318 anysumto(hand, n, s, t)
319 	const CARD hand[];
320 	int n, s, t;
321 {
322 	int i;
323 
324 	for (i = 0; i < n; i++) {
325 		if (s + VAL(hand[i].rank) == t)
326 			return (i);
327 	}
328 	return (-1);
329 }
330 
331 /*
332  * return the number of cards in h having the given rank value
333  */
334 int
335 numofval(h, n, v)
336 	const CARD h[];
337 	int n, v;
338 {
339 	int i, j;
340 
341 	j = 0;
342 	for (i = 0; i < n; i++) {
343 		if (VAL(h[i].rank) == v)
344 			++j;
345 	}
346 	return (j);
347 }
348 
349 /*
350  * makeknown remembers all n cards in h for future recall
351  */
352 void
353 makeknown(h, n)
354 	const CARD h[];
355 	int n;
356 {
357 	int i;
358 
359 	for (i = 0; i < n; i++)
360 		known[knownum++] = h[i];
361 }
362