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