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