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