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