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