xref: /openbsd-src/games/cribbage/support.c (revision b2ea75c1b17e1a9a339660e7ed45cd24946b230e)
1 /*	$OpenBSD: support.c,v 1.5 2001/08/10 23:50:22 pjanzen Exp $	*/
2 /*	$NetBSD: support.c,v 1.3 1995/03/21 15:08:59 cgd Exp $	*/
3 
4 /*-
5  * Copyright (c) 1980, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *	This product includes software developed by the University of
19  *	California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  */
36 
37 #ifndef lint
38 #if 0
39 static char sccsid[] = "@(#)support.c	8.1 (Berkeley) 5/31/93";
40 #else
41 static char rcsid[] = "$OpenBSD: support.c,v 1.5 2001/08/10 23:50:22 pjanzen 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 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 	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 	CARD    hand[];
133 	char   *s;
134 {
135 	static char prompt[BUFSIZ];
136 	int i, j;
137 	bool 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 			if (!win) {
148 				msg("It's really only %d points; I get %d", i, 2);
149 				win = chkscr(&cscore, 2);
150 			} else
151 				msg("It's really only %d points.", i);
152 		} else {
153 			win = chkscr(&pscore, j);
154 			msg("You should have taken %d, not %d!", i, j);
155 			if (!win && muggins) {
156 				msg("Muggins!  I score %d", i - j);
157 				win = chkscr(&cscore, i - j);
158 			}
159 		}
160 		if (explain)
161 			msg("Explanation: %s", expl);
162 		do_wait();
163 	} else
164 		win = chkscr(&pscore, i);
165 	return (win);
166 }
167 
168 /*
169  * comphand:
170  *	Handle scoring and displaying the computers hand
171  */
172 int
173 comphand(h, s)
174 	CARD h[];
175 	char *s;
176 {
177 	int j;
178 
179 	j = scorehand(h, turnover, CINHAND, strcmp(s, "crib") == 0, FALSE);
180 	prhand(h, CINHAND, Compwin, FALSE);
181 	msg("My %s scores %d", s, (j == 0 ? 19 : j));
182 	return (chkscr(&cscore, j));
183 }
184 
185 /*
186  * chkscr:
187  *	Add inc to scr and test for > glimit, printing on the scoring
188  *	board while we're at it.
189  */
190 int Lastscore[2] = {-1, -1};
191 
192 int
193 chkscr(scr, inc)
194 	int    *scr, inc;
195 {
196 	bool myturn;
197 
198 	myturn = (scr == &cscore);
199 	if (inc != 0) {
200 		prpeg(Lastscore[(int)myturn], '.', myturn);
201 		Lastscore[(int)myturn] = *scr;
202 		*scr += inc;
203 		prpeg(*scr, PEG, myturn);
204 		refresh();
205 	}
206 	return (*scr >= glimit);
207 }
208 
209 /*
210  * prpeg:
211  *	Put out the peg character on the score board and put the
212  *	score up on the board.
213  */
214 void
215 prpeg(score, peg, myturn)
216 	int score;
217 	int peg;
218 	bool myturn;
219 {
220 	int y, x;
221 
222 	if (!myturn)
223 		y = SCORE_Y + 2;
224 	else
225 		y = SCORE_Y + 5;
226 
227 	if (score <= 0 || score >= glimit) {
228 		if (peg == '.')
229 			peg = ' ';
230 		if (score == 0)
231 			x = SCORE_X + 2;
232 		else {
233 			x = SCORE_X + 2;
234 			y++;
235 		}
236 	} else {
237 		x = (score - 1) % 30;
238 		if (score > 90 || (score > 30 && score <= 60)) {
239 			y++;
240 			x = 29 - x;
241 		}
242 		x += x / 5;
243 		x += SCORE_X + 3;
244 	}
245 	mvaddch(y, x, peg);
246 	mvprintw(SCORE_Y + (myturn ? 7 : 1), SCORE_X + 10, "%3d", score);
247 }
248 
249 /*
250  * cdiscard -- the computer figures out what is the best discard for
251  * the crib and puts the best two cards at the end
252  */
253 void
254 cdiscard(mycrib)
255 	bool mycrib;
256 {
257 	CARD    d[CARDS], h[FULLHAND], cb[2];
258 	int i, j, k;
259 	int     nc, ns;
260 	long    sums[15];
261 	static int undo1[15] = {0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 3, 3, 4};
262 	static int undo2[15] = {1, 2, 3, 4, 5, 2, 3, 4, 5, 3, 4, 5, 4, 5, 5};
263 
264 	makedeck(d);
265 	nc = CARDS;
266 	for (i = 0; i < knownum; i++) {	/* get all other cards */
267 		cremove(known[i], d, nc--);
268 	}
269 	for (i = 0; i < 15; i++)
270 		sums[i] = 0L;
271 	ns = 0;
272 	for (i = 0; i < (FULLHAND - 1); i++) {
273 		cb[0] = chand[i];
274 		for (j = i + 1; j < FULLHAND; j++) {
275 			cb[1] = chand[j];
276 			for (k = 0; k < FULLHAND; k++)
277 				h[k] = chand[k];
278 			cremove(chand[i], h, FULLHAND);
279 			cremove(chand[j], h, FULLHAND - 1);
280 			for (k = 0; k < nc; k++) {
281 				sums[ns] +=
282 				    scorehand(h, d[k], CINHAND, TRUE, FALSE);
283 				if (mycrib)
284 					sums[ns] += adjust(cb, d[k]);
285 				else
286 					sums[ns] -= adjust(cb, d[k]);
287 			}
288 			++ns;
289 		}
290 	}
291 	j = 0;
292 	for (i = 1; i < 15; i++)
293 		if (sums[i] > sums[j])
294 			j = i;
295 	for (k = 0; k < FULLHAND; k++)
296 		h[k] = chand[k];
297 	cremove(h[undo1[j]], chand, FULLHAND);
298 	cremove(h[undo2[j]], chand, FULLHAND - 1);
299 	chand[4] = h[undo1[j]];
300 	chand[5] = h[undo2[j]];
301 }
302 
303 /*
304  * returns true if some card in hand can be played without exceeding 31
305  */
306 int
307 anymove(hand, n, sum)
308 	CARD hand[];
309 	int n, sum;
310 {
311 	int i, j;
312 
313 	if (n < 1)
314 		return (FALSE);
315 	j = hand[0].rank;
316 	for (i = 1; i < n; i++) {
317 		if (hand[i].rank < j)
318 			j = hand[i].rank;
319 	}
320 	return (sum + VAL(j) <= 31);
321 }
322 
323 /*
324  * anysumto returns the index (0 <= i < n) of the card in hand that brings
325  * the s up to t, or -1 if there is none
326  */
327 int
328 anysumto(hand, n, s, t)
329 	CARD hand[];
330 	int n, s, t;
331 {
332 	int i;
333 
334 	for (i = 0; i < n; i++) {
335 		if (s + VAL(hand[i].rank) == t)
336 			return (i);
337 	}
338 	return (-1);
339 }
340 
341 /*
342  * return the number of cards in h having the given rank value
343  */
344 int
345 numofval(h, n, v)
346 	CARD h[];
347 	int n, v;
348 {
349 	int i, j;
350 
351 	j = 0;
352 	for (i = 0; i < n; i++) {
353 		if (VAL(h[i].rank) == v)
354 			++j;
355 	}
356 	return (j);
357 }
358 
359 /*
360  * makeknown remembers all n cards in h for future recall
361  */
362 void
363 makeknown(h, n)
364 	CARD h[];
365 	int n;
366 {
367 	int i;
368 
369 	for (i = 0; i < n; i++)
370 		known[knownum++] = h[i];
371 }
372