1 /*- 2 * Copyright (c) 1980, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * @(#)support.c 8.1 (Berkeley) 5/31/93 34 * $FreeBSD: src/games/cribbage/support.c,v 1.5 1999/12/12 03:04:15 billf Exp $ 35 * $DragonFly: src/games/cribbage/support.c,v 1.3 2005/08/03 13:31:00 eirikn Exp $ 36 */ 37 38 #include <stdio.h> 39 #include <string.h> 40 41 #include "cribbage.h" 42 #include "cribcur.h" 43 44 static int anysumto(CARD[], int, int, int); 45 static int numofval(CARD[], int, int); 46 static void prpeg(int, int, bool); 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(CARD h[], int n, int s) 59 { 60 int i, j, l; 61 62 if (n <= 1) 63 return (0); 64 if (s < 4) { /* try for good value */ 65 if ((j = anysumto(h, n, s, 4)) >= 0) 66 return (j); 67 if ((j = anysumto(h, n, s, 3)) >= 0 && s == 0) 68 return (j); 69 } 70 if (s > 0 && s < 20) { 71 /* try for retaliation to 31 */ 72 for (i = 1; i <= 10; i++) { 73 if ((j = anysumto(h, n, s, 21 - i)) >= 0) { 74 if ((l = numofval(h, n, i)) > 0) { 75 if (l > 1 || VAL(h[j].rank) != i) 76 return (j); 77 } 78 } 79 } 80 } 81 if (s < 15) { 82 /* for retaliation after 15 */ 83 for (i = 0; i < NTV; i++) { 84 if ((j = anysumto(h, n, s, tv[i])) >= 0) { 85 if ((l = numofval(h, n, 15 - tv[i])) > 0) { 86 if (l > 1 || 87 VAL(h[j].rank) != 15 - tv[i]) 88 return (j); 89 } 90 } 91 } 92 } 93 j = -1; 94 /* remember: h is sorted */ 95 for (i = n - 1; i >= 0; --i) { 96 l = s + VAL(h[i].rank); 97 if (l > 31) 98 continue; 99 if (l != 5 && l != 10 && l != 21) { 100 j = i; 101 break; 102 } 103 } 104 if (j >= 0) 105 return (j); 106 for (i = n - 1; i >= 0; --i) { 107 l = s + VAL(h[i].rank); 108 if (l > 31) 109 continue; 110 if (j < 0) 111 j = i; 112 if (l != 5 && l != 21) { 113 j = i; 114 break; 115 } 116 } 117 return (j); 118 } 119 120 /* 121 * plyrhand: 122 * Evaluate and score a player hand or crib 123 */ 124 bool 125 plyrhand(CARD hand[], const char *s) 126 { 127 static char prompt[BUFSIZ]; 128 int i, j; 129 bool win; 130 131 prhand(hand, CINHAND, Playwin, false); 132 sprintf(prompt, "Your %s scores ", s); 133 i = scorehand(hand, turnover, CINHAND, strcmp(s, "crib") == 0, explain); 134 if ((j = number(0, 29, prompt)) == 19) 135 j = 0; 136 if (i != j) { 137 if (i < j) { 138 win = chkscr(&pscore, i); 139 msg("It's really only %d points; I get %d", i, 2); 140 if (!win) 141 win = chkscr(&cscore, 2); 142 } else { 143 win = chkscr(&pscore, j); 144 msg("You should have taken %d, not %d!", i, j); 145 } 146 if (explain) 147 msg("Explanation: %s", explstr); 148 do_wait(); 149 } else 150 win = chkscr(&pscore, i); 151 return (win); 152 } 153 154 /* 155 * comphand: 156 * Handle scoring and displaying the computer's hand 157 */ 158 bool 159 comphand(CARD h[], const char *s) 160 { 161 int j; 162 163 j = scorehand(h, turnover, CINHAND, strcmp(s, "crib") == 0, false); 164 prhand(h, CINHAND, Compwin, false); 165 msg("My %s scores %d", s, (j == 0 ? 19 : j)); 166 return (chkscr(&cscore, j)); 167 } 168 169 /* 170 * chkscr: 171 * Add inc to scr and test for > glimit, printing on the scoring 172 * board while we're at it. 173 */ 174 int Lastscore[2] = {-1, -1}; 175 176 bool 177 chkscr(int *scr, int inc) 178 { 179 bool myturn; 180 181 myturn = (scr == &cscore); 182 if (inc != 0) { 183 prpeg(Lastscore[myturn], '.', myturn); 184 Lastscore[myturn] = *scr; 185 *scr += inc; 186 prpeg(*scr, PEG, myturn); 187 refresh(); 188 } 189 return (*scr >= glimit); 190 } 191 192 /* 193 * prpeg: 194 * Put out the peg character on the score board and put the 195 * score up on the board. 196 */ 197 static void 198 prpeg(int score, int peg, bool myturn) 199 { 200 int y, x; 201 202 if (!myturn) 203 y = SCORE_Y + 2; 204 else 205 y = SCORE_Y + 5; 206 207 if (score <= 0 || score >= glimit) { 208 if (peg == '.') 209 peg = ' '; 210 if (score == 0) 211 x = SCORE_X + 2; 212 else { 213 x = SCORE_X + 2; 214 y++; 215 } 216 } else { 217 x = (score - 1) % 30; 218 if (score > 90 || (score > 30 && score <= 60)) { 219 y++; 220 x = 29 - x; 221 } 222 x += x / 5; 223 x += SCORE_X + 3; 224 } 225 mvaddch(y, x, peg); 226 mvprintw(SCORE_Y + (myturn ? 7 : 1), SCORE_X + 10, "%3d", score); 227 } 228 229 /* 230 * cdiscard -- the computer figures out what is the best discard for 231 * the crib and puts the best two cards at the end 232 */ 233 void 234 cdiscard(bool mycrib) 235 { 236 CARD d[CARDS], h[FULLHAND], cb[2]; 237 int i, j, k; 238 int nc, ns; 239 long sums[15]; 240 static int undo1[15] = {0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 3, 3, 4}; 241 static int undo2[15] = {1, 2, 3, 4, 5, 2, 3, 4, 5, 3, 4, 5, 4, 5, 5}; 242 243 makedeck(d); 244 nc = CARDS; 245 for (i = 0; i < knownum; i++) { /* get all other cards */ 246 cremove(known[i], d, nc--); 247 } 248 for (i = 0; i < 15; i++) 249 sums[i] = 0L; 250 ns = 0; 251 for (i = 0; i < (FULLHAND - 1); i++) { 252 cb[0] = chand[i]; 253 for (j = i + 1; j < FULLHAND; j++) { 254 cb[1] = chand[j]; 255 for (k = 0; k < FULLHAND; k++) 256 h[k] = chand[k]; 257 cremove(chand[i], h, FULLHAND); 258 cremove(chand[j], h, FULLHAND - 1); 259 for (k = 0; k < nc; k++) { 260 sums[ns] += 261 scorehand(h, d[k], CINHAND, true, false); 262 if (mycrib) 263 sums[ns] += adjust(cb); 264 else 265 sums[ns] -= adjust(cb); 266 } 267 ++ns; 268 } 269 } 270 j = 0; 271 for (i = 1; i < 15; i++) 272 if (sums[i] > sums[j]) 273 j = i; 274 for (k = 0; k < FULLHAND; k++) 275 h[k] = chand[k]; 276 cremove(h[undo1[j]], chand, FULLHAND); 277 cremove(h[undo2[j]], chand, FULLHAND - 1); 278 chand[4] = h[undo1[j]]; 279 chand[5] = h[undo2[j]]; 280 } 281 282 /* 283 * returns true if some card in hand can be played without exceeding 31 284 */ 285 bool 286 anymove(CARD hand[], int n, int sum) 287 { 288 int i, j; 289 290 if (n < 1) 291 return (false); 292 j = hand[0].rank; 293 for (i = 1; i < n; i++) { 294 if (hand[i].rank < j) 295 j = hand[i].rank; 296 } 297 return (sum + VAL(j) <= 31); 298 } 299 300 /* 301 * anysumto returns the index (0 <= i < n) of the card in hand that brings 302 * the s up to t, or -1 if there is none 303 */ 304 static int 305 anysumto(CARD hand[], int n, int s, int t) 306 { 307 int i; 308 309 for (i = 0; i < n; i++) { 310 if (s + VAL(hand[i].rank) == t) 311 return (i); 312 } 313 return (-1); 314 } 315 316 /* 317 * return the number of cards in h having the given rank value 318 */ 319 static int 320 numofval(CARD h[], int n, int v) 321 { 322 int i, j; 323 324 j = 0; 325 for (i = 0; i < n; i++) { 326 if (VAL(h[i].rank) == v) 327 ++j; 328 } 329 return (j); 330 } 331 332 /* 333 * makeknown remembers all n cards in h for future recall 334 */ 335 void 336 makeknown(CARD h[], int n) 337 { 338 int i; 339 340 for (i = 0; i < n; i++) 341 known[knownum++] = h[i]; 342 } 343