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