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