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