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