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