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