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