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