1 /*- 2 * Copyright (c) 1982, 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 * @(#)comp.c 8.1 (Berkeley) 5/31/93 30 * $FreeBSD: src/games/mille/comp.c,v 1.5 1999/12/12 06:17:24 billf Exp $ 31 */ 32 33 #include "mille.h" 34 35 /* 36 * @(#)comp.c 1.1 (Berkeley) 4/1/82 37 */ 38 39 #define V_VALUABLE 40 40 41 void 42 calcmove(void) 43 { 44 CARD card; 45 int *value; 46 PLAY *pp, *op; 47 bool foundend, cango, canstop, foundlow; 48 unsigned int i, count200, badcount, nummin, nummax, diff; 49 int curmin, curmax; 50 CARD safe, oppos; 51 int valbuf[HAND_SZ], count[NUM_CARDS]; 52 bool playit[HAND_SZ]; 53 54 wmove(Score, ERR_Y, ERR_X); /* get rid of error messages */ 55 wclrtoeol(Score); 56 pp = &Player[COMP]; 57 op = &Player[PLAYER]; 58 safe = 0; 59 cango = FALSE; 60 canstop = FALSE; 61 foundend = FALSE; 62 63 /* Try for a Coup Forre, and see what we have. */ 64 for (i = 0; i < NUM_CARDS; i++) 65 count[i] = 0; 66 for (i = 0; i < HAND_SZ; i++) { 67 card = pp->hand[i]; 68 switch (card) { 69 case C_STOP: case C_CRASH: 70 case C_FLAT: case C_EMPTY: 71 if ((playit[i] = canplay(pp, op, card))) 72 canstop = TRUE; 73 goto norm; 74 case C_LIMIT: 75 if ((playit[i] = canplay(pp, op, card)) 76 && Numseen[C_25] == Numcards[C_25] 77 && Numseen[C_50] == Numcards[C_50]) 78 canstop = TRUE; 79 goto norm; 80 case C_25: case C_50: case C_75: 81 case C_100: case C_200: 82 if ((playit[i] = canplay(pp, op, card)) 83 && pp->mileage + Value[card] == End) 84 foundend = TRUE; 85 goto norm; 86 default: 87 playit[i] = canplay(pp, op, card); 88 norm: 89 if (playit[i]) 90 cango = TRUE; 91 break; 92 case C_GAS_SAFE: case C_DRIVE_SAFE: 93 case C_SPARE_SAFE: case C_RIGHT_WAY: 94 if (pp->battle == opposite(card) || 95 (pp->speed == C_LIMIT && card == C_RIGHT_WAY)) { 96 Movetype = M_PLAY; 97 Card_no = i; 98 return; 99 } 100 ++safe; 101 playit[i] = TRUE; 102 break; 103 } 104 if (card >= 0) 105 ++count[card]; 106 } 107 108 /* No Coup Forre. Draw to fill hand, then restart, as needed. */ 109 if (pp->hand[0] == C_INIT && Topcard > Deck) { 110 Movetype = M_DRAW; 111 return; 112 } 113 114 #ifdef DEBUG 115 if (Debug) 116 fprintf(outf, "CALCMOVE: cango = %d, canstop = %d, safe = %d\n", 117 cango, canstop, safe); 118 #endif 119 if (foundend) 120 foundend = !check_ext(TRUE); 121 for (i = 0; safe && i < HAND_SZ; i++) { 122 if (issafety(pp->hand[i])) { 123 if (onecard(op) || (foundend && cango && !canstop)) { 124 #ifdef DEBUG 125 if (Debug) 126 fprintf(outf, 127 "CALCMOVE: onecard(op) = %d, foundend = %d\n", 128 onecard(op), foundend); 129 #endif 130 playsafe: 131 Movetype = M_PLAY; 132 Card_no = i; 133 return; 134 } 135 oppos = opposite(pp->hand[i]); 136 if (Numseen[oppos] == Numcards[oppos] && 137 !(pp->hand[i] == C_RIGHT_WAY && 138 Numseen[C_LIMIT] != Numcards[C_LIMIT])) 139 goto playsafe; 140 else if (!cango 141 && (op->can_go || !pp->can_go || Topcard < Deck)) { 142 card = (Topcard - Deck) - roll(1, 10); 143 if ((!pp->mileage) != (!op->mileage)) 144 card -= 7; 145 #ifdef DEBUG 146 if (Debug) 147 fprintf(outf, 148 "CALCMOVE: card = %d, DECK_SZ / 4 = %d\n", 149 card, DECK_SZ / 4); 150 #endif 151 if (card < DECK_SZ / 4) 152 goto playsafe; 153 } 154 safe--; 155 playit[i] = cango; 156 } 157 } 158 if (!pp->can_go && !isrepair(pp->battle)) 159 Numneed[opposite(pp->battle)]++; 160 redoit: 161 foundlow = (cango || count[C_END_LIMIT] != 0 162 || Numseen[C_LIMIT] == Numcards[C_LIMIT] 163 || pp->safety[S_RIGHT_WAY] != S_UNKNOWN); 164 foundend = FALSE; 165 count200 = pp->nummiles[C_200]; 166 badcount = 0; 167 curmax = -1; 168 curmin = 101; 169 nummin = -1; 170 nummax = -1; 171 value = valbuf; 172 for (i = 0; i < HAND_SZ; i++) { 173 card = pp->hand[i]; 174 if (issafety(card) || playit[i] == cango) { 175 #ifdef DEBUG 176 if (Debug) 177 fprintf(outf, "CALCMOVE: switch(\"%s\")\n", 178 C_name[card]); 179 #endif 180 switch (card) { 181 case C_25: case C_50: 182 diff = End - pp->mileage; 183 /* avoid getting too close */ 184 if (Topcard > Deck && cango && diff <= 100 185 && (int)diff / Value[card] > count[card] 186 && (card == C_25 || diff % 50 == 0)) { 187 if (card == C_50 && diff - 50 == 25 188 && count[C_25] > 0) 189 goto okay; 190 *value = 0; 191 cango = FALSE; 192 goto redoit; 193 } 194 okay: 195 *value = (Value[card] >> 3); 196 if (pp->speed == C_LIMIT) 197 ++*value; 198 else 199 --*value; 200 if (!foundlow 201 && (card == C_50 || count[C_50] == 0)) { 202 *value = (pp->mileage ? 10 : 20); 203 foundlow = TRUE; 204 } 205 goto miles; 206 case C_200: 207 if (++count200 > 2) { 208 *value = 0; 209 break; 210 } 211 /* FALLTHROUGH */ 212 case C_100: 213 case C_75: 214 *value = (Value[card] >> 3); 215 if (pp->speed == C_LIMIT) 216 --*value; 217 else 218 ++*value; 219 miles: 220 if (pp->mileage + Value[card] > End) 221 *value = (End == 700 ? card : 0); 222 else if (pp->mileage + Value[card] == End) { 223 *value = (foundend ? card : V_VALUABLE); 224 foundend = TRUE; 225 } 226 break; 227 case C_END_LIMIT: 228 if (pp->safety[S_RIGHT_WAY] != S_UNKNOWN) 229 *value = (pp->safety[S_RIGHT_WAY] == 230 S_PLAYED ? -1 : 1); 231 else if (pp->speed == C_LIMIT && 232 End - pp->mileage <= 50) 233 *value = 1; 234 else if (pp->speed == C_LIMIT 235 || Numseen[C_LIMIT] != Numcards[C_LIMIT]) { 236 safe = S_RIGHT_WAY; 237 oppos = C_LIMIT; 238 goto repair; 239 } 240 else { 241 *value = 0; 242 --count[C_END_LIMIT]; 243 } 244 break; 245 case C_REPAIRS: case C_SPARE: case C_GAS: 246 safe = safety(card) - S_CONV; 247 oppos = opposite(card); 248 if (pp->safety[safe] != S_UNKNOWN) 249 *value = (pp->safety[safe] == 250 S_PLAYED ? -1 : 1); 251 else if (pp->battle != oppos 252 && (Numseen[oppos] == Numcards[oppos] || 253 Numseen[oppos] + count[card] > 254 Numcards[oppos])) { 255 *value = 0; 256 --count[card]; 257 } 258 else { 259 repair: 260 *value = Numcards[oppos] * 6; 261 *value += Numseen[card] - 262 Numseen[oppos]; 263 if (!cango) 264 *value /= (count[card]*count[card]); 265 count[card]--; 266 } 267 break; 268 case C_GO: 269 if (pp->safety[S_RIGHT_WAY] != S_UNKNOWN) 270 *value = (pp->safety[S_RIGHT_WAY] == 271 S_PLAYED ? -1 : 2); 272 else if (pp->can_go 273 && Numgos + count[C_GO] == Numneed[C_GO]) { 274 *value = 0; 275 --count[C_GO]; 276 } 277 else { 278 *value = Numneed[C_GO] * 3; 279 *value += (Numseen[C_GO] - Numgos); 280 *value /= (count[C_GO] * count[C_GO]); 281 count[C_GO]--; 282 } 283 break; 284 case C_LIMIT: 285 if (op->mileage + 50 >= End) { 286 *value = (End == 700 && !cango); 287 break; 288 } 289 if (canstop || (cango && !op->can_go)) 290 *value = 1; 291 else { 292 *value = (pp->safety[S_RIGHT_WAY] != 293 S_UNKNOWN ? 2 : 3); 294 safe = S_RIGHT_WAY; 295 oppos = C_END_LIMIT; 296 goto normbad; 297 } 298 break; 299 case C_CRASH: case C_EMPTY: case C_FLAT: 300 safe = safety(card) - S_CONV; 301 oppos = opposite(card); 302 *value = (pp->safety[safe]!=S_UNKNOWN ? 3 : 4); 303 normbad: 304 if (op->safety[safe] == S_PLAYED) 305 *value = -1; 306 else { 307 *value *= Numneed[oppos] + 308 Numseen[oppos] + 2; 309 if (!pp->mileage || foundend || 310 onecard(op)) 311 *value += 5; 312 if (op->mileage == 0 || onecard(op)) 313 *value += 5; 314 if (op->speed == C_LIMIT) 315 *value -= 3; 316 if (cango && 317 pp->safety[safe] != S_UNKNOWN) 318 *value += 3; 319 if (!cango) 320 *value /= ++badcount; 321 } 322 break; 323 case C_STOP: 324 if (op->safety[S_RIGHT_WAY] == S_PLAYED) 325 *value = -1; 326 else { 327 *value = (pp->safety[S_RIGHT_WAY] != 328 S_UNKNOWN ? 3 : 4); 329 *value *= Numcards[C_STOP] + 330 Numseen[C_GO]; 331 if (!pp->mileage || foundend || 332 onecard(op)) 333 *value += 5; 334 if (!cango) 335 *value /= ++badcount; 336 if (op->mileage == 0) 337 *value += 5; 338 if ((card == C_LIMIT && 339 op->speed == C_LIMIT) || 340 !op->can_go) 341 *value -= 5; 342 if (cango && pp->safety[S_RIGHT_WAY] != 343 S_UNKNOWN) 344 *value += 5; 345 } 346 break; 347 case C_GAS_SAFE: case C_DRIVE_SAFE: 348 case C_SPARE_SAFE: case C_RIGHT_WAY: 349 *value = cango ? 0 : 101; 350 break; 351 case C_INIT: 352 *value = 0; 353 break; 354 } 355 } 356 else 357 *value = cango ? 0 : 101; 358 if (card != C_INIT) { 359 if (*value >= curmax) { 360 nummax = i; 361 curmax = *value; 362 } 363 if (*value <= curmin) { 364 nummin = i; 365 curmin = *value; 366 } 367 } 368 #ifdef DEBUG 369 if (Debug) 370 mvprintw(i + 6, 2, "%3d %-14s", *value, 371 C_name[pp->hand[i]]); 372 #endif 373 value++; 374 } 375 if (!pp->can_go && !isrepair(pp->battle)) 376 Numneed[opposite(pp->battle)]++; 377 if (cango) { 378 play_it: 379 mvaddstr(MOVE_Y + 1, MOVE_X, "PLAY\n"); 380 Movetype = M_PLAY; 381 Card_no = nummax; 382 } 383 else { 384 if (issafety(pp->hand[nummin])) { /* NEVER discard a safety */ 385 nummax = nummin; 386 goto play_it; 387 } 388 mvaddstr(MOVE_Y + 1, MOVE_X, "DISCARD\n"); 389 Movetype = M_DISCARD; 390 Card_no = nummin; 391 } 392 mvprintw(MOVE_Y + 2, MOVE_X, "%16s", C_name[pp->hand[Card_no]]); 393 } 394 395 /* 396 * Return true if the given player could conceivably win with his next card. 397 */ 398 bool 399 onecard(const PLAY *pp) 400 { 401 CARD bat, spd, card; 402 403 bat = pp->battle; 404 spd = pp->speed; 405 card = -1; 406 if (pp->can_go || ((isrepair(bat) || bat == C_STOP || spd == C_LIMIT) && 407 Numseen[S_RIGHT_WAY] != 0) || 408 (bat >= 0 && Numseen[safety(bat)] != 0)) 409 switch (End - pp->mileage) { 410 case 200: 411 if (pp->nummiles[C_200] == 2) 412 return FALSE; 413 card = C_200; 414 /* FALLTHROUGH */ 415 case 100: 416 case 75: 417 if (card == -1) 418 card = (End - pp->mileage == 75 ? C_75 : C_100); 419 if (spd == C_LIMIT) 420 return Numseen[S_RIGHT_WAY] == 0; 421 /* FALLTHROUGH */ 422 case 50: 423 case 25: 424 if (card == -1) 425 card = (End - pp->mileage == 25 ? C_25 : C_50); 426 return Numseen[card] != Numcards[card]; 427 } 428 return FALSE; 429 } 430 431 bool 432 canplay(const PLAY *pp, const PLAY *op, CARD card) 433 { 434 switch (card) { 435 case C_200: 436 if (pp->nummiles[C_200] == 2) 437 break; 438 /* FALLTHROUGH */ 439 case C_75: case C_100: 440 if (pp->speed == C_LIMIT) 441 break; 442 /* FALLTHROUGH */ 443 case C_50: 444 if (pp->mileage + Value[card] > End) 445 break; 446 /* FALLTHROUGH */ 447 case C_25: 448 if (pp->can_go) 449 return TRUE; 450 break; 451 case C_EMPTY: case C_FLAT: case C_CRASH: 452 case C_STOP: 453 if (op->can_go && op->safety[safety(card) - S_CONV] != S_PLAYED) 454 return TRUE; 455 break; 456 case C_LIMIT: 457 if (op->speed != C_LIMIT && 458 op->safety[S_RIGHT_WAY] != S_PLAYED && 459 op->mileage + 50 < End) 460 return TRUE; 461 break; 462 case C_GAS: case C_SPARE: case C_REPAIRS: 463 if (pp->battle == opposite(card)) 464 return TRUE; 465 break; 466 case C_GO: 467 if (!pp->can_go && 468 (isrepair(pp->battle) || pp->battle == C_STOP)) 469 return TRUE; 470 break; 471 case C_END_LIMIT: 472 if (pp->speed == C_LIMIT) 473 return TRUE; 474 } 475 return FALSE; 476 } 477