Merge branch 'vendor/LDNS'
[dragonfly.git] / games / cribbage / score.c
1 /*-
2  * Copyright (c) 1980, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the University nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * @(#)score.c  8.1 (Berkeley) 5/31/93
30  * $FreeBSD: src/games/cribbage/score.c,v 1.6 1999/11/30 03:48:47 billf Exp $
31  * $DragonFly: src/games/cribbage/score.c,v 1.3 2005/08/03 13:31:00 eirikn Exp $
32  */
33
34 #include <curses.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38
39 #include "deck.h"
40 #include "cribbage.h"
41
42 static int fifteens(CARD[], int);
43 static int pairuns(CARD[], int);
44 /*
45  * the following arrays give the sum of the scores of the (50 2)*48 = 58800
46  * hands obtainable for the crib given the two cards whose ranks index the
47  * array.  the two arrays are for the case where the suits are equal and
48  * not equal respectively
49  */
50 const long crbescr[169] = {
51     -10000, 271827, 278883, 332319, 347769, 261129, 250653, 253203, 248259,
52     243435, 256275, 237435, 231051, -10000, -10000, 412815, 295707, 349497,
53     267519, 262521, 259695, 254019, 250047, 262887, 244047, 237663, -10000,
54     -10000, -10000, 333987, 388629, 262017, 266787, 262971, 252729, 254475,
55     267315, 248475, 242091, -10000, -10000, -10000, -10000, 422097, 302787,
56     256437, 263751, 257883, 254271, 267111, 248271, 241887, -10000, -10000,
57     -10000, -10000, -10000, 427677, 387837, 349173, 347985, 423861, 436701,
58     417861, 411477, -10000, -10000, -10000, -10000, -10000, -10000, 336387,
59     298851, 338667, 236487, 249327, 230487, 224103, -10000, -10000, -10000,
60     -10000, -10000, -10000, -10000, 408483, 266691, 229803, 246195, 227355,
61     220971, -10000, -10000, -10000, -10000, -10000, -10000, -10000, -10000,
62     300675, 263787, 241695, 226407, 220023, -10000, -10000, -10000, -10000,
63     -10000, -10000, -10000, -10000, -10000, 295635, 273543, 219771, 216939,
64     -10000, -10000, -10000, -10000, -10000, -10000, -10000, -10000, -10000,
65     -10000, 306519, 252747, 211431, -10000, -10000, -10000, -10000, -10000,
66     -10000, -10000, -10000, -10000, -10000, -10000, 304287, 262971, -10000,
67     -10000, -10000, -10000, -10000, -10000, -10000, -10000, -10000, -10000,
68     -10000, -10000, 244131, -10000, -10000, -10000, -10000, -10000, -10000,
69     -10000, -10000, -10000, -10000, -10000, -10000, -10000
70 };
71
72 const long crbnescr[169] = {
73     325272, 260772, 267828, 321264, 336714, 250074, 239598, 242148, 237204,
74     232380, 246348, 226380, 219996, -10000, 342528, 401760, 284652, 338442,
75     256464, 251466, 248640, 242964, 238992, 252960, 232992, 226608, -10000,
76     -10000, 362280, 322932, 377574, 250962, 255732, 251916, 241674, 243420,
77     257388, 237420, 231036, -10000, -10000, -10000, 360768, 411042, 291732,
78     245382, 252696, 246828, 243216, 257184, 237216, 230832, -10000, -10000,
79     -10000, -10000, 528768, 416622, 376782, 338118, 336930, 412806, 426774,
80     406806, 400422, -10000, -10000, -10000, -10000, -10000, 369864, 325332,
81     287796, 327612, 225432, 239400, 219432, 213048, -10000, -10000, -10000,
82     -10000, -10000, -10000, 359160, 397428, 255636, 218748, 236268, 216300,
83     209916, -10000, -10000, -10000, -10000, -10000, -10000, -10000, 331320,
84     289620, 252732, 231768, 215352, 208968, -10000, -10000, -10000, -10000,
85     -10000, -10000, -10000, -10000, 325152, 284580, 263616, 208716, 205884,
86     -10000, -10000, -10000, -10000, -10000, -10000, -10000, -10000, -10000,
87     321240, 296592, 241692, 200376, -10000, -10000, -10000, -10000, -10000,
88     -10000, -10000, -10000, -10000, -10000, 348600, 294360, 253044, -10000,
89     -10000, -10000, -10000, -10000, -10000, -10000, -10000, -10000, -10000,
90     -10000, 308664, 233076, -10000, -10000, -10000, -10000, -10000, -10000,
91     -10000, -10000, -10000, -10000, -10000, -10000, 295896
92 };
93
94 static const int ichoose2[5] = { 0, 0, 2, 6, 12 };
95 static int pairpoints, runpoints;               /* Globals from pairuns. */
96
97 /*
98  * scorehand:
99  *      Score the given hand of n cards and the starter card.
100  *      n must be <= 4
101  *      crb is true if scoring crib
102  *      do_explain is true if must explain this hand
103  */
104 int
105 scorehand(CARD hand[], CARD starter, int n, bool crb, bool do_explain)
106 {
107         int i, k;
108         int score;
109         bool flag;
110         CARD h[(CINHAND + 1)];
111         char buf[32];
112
113         explstr[0] = '\0';              /* initialize explanation */
114         score = 0;
115         flag = true;
116         k = hand[0].suit;
117         for (i = 0; i < n; i++) {       /* check for flush */
118                 flag = (flag && (hand[i].suit == k));
119                 if (hand[i].rank == JACK)       /* check for his nibs */
120                         if (hand[i].suit == starter.suit) {
121                                 score++;
122                                 if (do_explain)
123                                         strcat(explstr, "His Nobs");
124                         }
125                 h[i] = hand[i];
126         }
127
128         if (flag && n >= CINHAND) {
129                 if (do_explain && explstr[0] != '\0')
130                         strcat(explstr, ", ");
131                 if (starter.suit == k) {
132                         score += 5;
133                         if (do_explain)
134                                 strcat(explstr, "Five-flush");
135                 } else
136                         if (!crb) {
137                                 score += 4;
138                                 if (do_explain && explstr[0] != '\0')
139                                         strcat(explstr, ", Four-flush");
140                                 else
141                                         strcpy(explstr, "Four-flush");
142                         }
143         }
144         if (do_explain && explstr[0] != '\0')
145                 strcat(explstr, ", ");
146         h[n] = starter;
147         sorthand(h, n + 1);     /* sort by rank */
148         i = 2 * fifteens(h, n + 1);
149         score += i;
150         if (do_explain) {
151                 if (i > 0) {
152                         sprintf(buf, "%d points in fifteens", i);
153                         strcat(explstr, buf);
154                 } else
155                         strcat(explstr, "No fifteens");
156         }
157         i = pairuns(h, n + 1);
158         score += i;
159         if (do_explain) {
160                 if (i > 0) {
161                         sprintf(buf, ", %d points in pairs, %d in runs",
162                             pairpoints, runpoints);
163                         strcat(explstr, buf);
164                 } else
165                         strcat(explstr, ", No pairs/runs");
166         }
167         return (score);
168 }
169
170 /*
171  * fifteens:
172  *      Return number of fifteens in hand of n cards
173  */
174 static int
175 fifteens(CARD hand[], int n)
176 {
177         int *sp, *np;
178         int i;
179         CARD *endp;
180         static int sums[15], nsums[15];
181
182         np = nsums;
183         sp = sums;
184         i = 16;
185         while (--i) {
186                 *np++ = 0;
187                 *sp++ = 0;
188         }
189         for (endp = &hand[n]; hand < endp; hand++) {
190                 i = hand->rank + 1;
191                 if (i > 10)
192                         i = 10;
193                 np = &nsums[i];
194                 np[-1]++;       /* one way to make this */
195                 sp = sums;
196                 while (i < 15) {
197                         *np++ += *sp++;
198                         i++;
199                 }
200                 sp = sums;
201                 np = nsums;
202                 i = 16;
203                 while (--i)
204                         *sp++ = *np++;
205         }
206         return sums[14];
207 }
208
209 /*
210  * pairuns returns the number of points in the n card sorted hand
211  * due to pairs and runs
212  * this routine only works if n is strictly less than 6
213  * sets the globals pairpoints and runpoints appropriately
214  */
215 static int
216 pairuns(CARD h[], int n)
217 {
218         int i;
219         int runlength, runmult, lastmult, curmult;
220         int mult1, mult2, pair1, pair2;
221         bool run;
222
223         run = true;
224         runlength = 1;
225         mult1 = 1;
226         pair1 = -1;
227         mult2 = 1;
228         pair2 = -1;
229         curmult = runmult = 1;
230         for (i = 1; i < n; i++) {
231                 lastmult = curmult;
232                 if (h[i].rank == h[i - 1].rank) {
233                         if (pair1 < 0) {
234                                 pair1 = h[i].rank;
235                                 mult1 = curmult = 2;
236                         } else {
237                                 if (h[i].rank == pair1) {
238                                         curmult = ++mult1;
239                                 } else {
240                                         if (pair2 < 0) {
241                                                 pair2 = h[i].rank;
242                                                 mult2 = curmult = 2;
243                                         } else {
244                                                 curmult = ++mult2;
245                                         }
246                                 }
247                         }
248                         if (i == (n - 1) && run) {
249                                 runmult *= curmult;
250                         }
251                 } else {
252                         curmult = 1;
253                         if (h[i].rank == h[i - 1].rank + 1) {
254                                 if (run) {
255                                         ++runlength;
256                                 } else {
257                                                         /* only if old short */
258                                         if (runlength < 3) {
259                                                 run = true;
260                                                 runlength = 2;
261                                                 runmult = 1;
262                                         }
263                                 }
264                                 runmult *= lastmult;
265                         } else {
266                                                         /* if just ended */
267                                 if (run)
268                                         runmult *= lastmult;
269                                 run = false;
270                         }
271                 }
272         }
273         pairpoints = ichoose2[mult1] + ichoose2[mult2];
274         runpoints = (runlength >= 3 ? runlength * runmult : 0);
275         return (pairpoints + runpoints);
276 }
277
278 /*
279  * pegscore tells how many points crd would get if played after
280  * the n cards in tbl during pegging
281  */
282 int
283 pegscore(CARD crd, CARD tbl[], int n, int sum)
284 {
285         bool got[RANKS];
286         int i, j, scr;
287         int k, lo, hi;
288
289         sum += VAL(crd.rank);
290         if (sum > 31)
291                 return (-1);
292         if (sum == 31 || sum == 15)
293                 scr = 2;
294         else
295                 scr = 0;
296         if (!n)
297                 return (scr);
298         j = 1;
299         while ((crd.rank == tbl[n - j].rank) && (n - j >= 0))
300                 ++j;
301         if (j > 1)
302                 return (scr + ichoose2[j]);
303         if (n < 2)
304                 return (scr);
305         lo = hi = crd.rank;
306         for (i = 0; i < RANKS; i++)
307                 got[i] = false;
308         got[crd.rank] = true;
309         k = -1;
310         for (i = n - 1; i >= 0; --i) {
311                 if (got[tbl[i].rank])
312                         break;
313                 got[tbl[i].rank] = true;
314                 if (tbl[i].rank < lo)
315                         lo = tbl[i].rank;
316                 if (tbl[i].rank > hi)
317                         hi = tbl[i].rank;
318                 for (j = lo; j <= hi; j++)
319                         if (!got[j])
320                                 break;
321                 if (j > hi)
322                         k = hi - lo + 1;
323         }
324         if (k >= 3)
325                 return (scr + k);
326         else
327                 return (scr);
328 }
329
330 /*
331  * adjust takes a two card hand that will be put in the crib
332  * and returns an adjusted normalized score for the number of
333  * points such a crib will get.
334  */
335 int
336 adjust(CARD cb[])
337 {
338         long scr;
339         int i, c0, c1;
340
341         c0 = cb[0].rank;
342         c1 = cb[1].rank;
343         if (c0 > c1) {
344                 i = c0;
345                 c0 = c1;
346                 c1 = i;
347         }
348         if (cb[0].suit != cb[1].suit)
349                 scr = crbnescr[RANKS * c0 + c1];
350         else
351                 scr = crbescr[RANKS * c0 + c1];
352         if (scr <= 0) {
353                 printf("\nADJUST: internal error %d %d\n", c0, c1);
354                 exit(93);
355         }
356         return ((scr + 29400) / 58800);
357 }