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 * $DragonFly: src/games/mille/comp.c,v 1.4 2008/06/05 18:06:30 swildner Exp $ 32 */ 33 34 #include "mille.h" 35 36 /* 37 * @(#)comp.c 1.1 (Berkeley) 4/1/82 38 */ 39 40 #define V_VALUABLE 40 41 42 void 43 calcmove(void) 44 { 45 CARD card; 46 int *value; 47 PLAY *pp, *op; 48 bool foundend, cango, canstop, foundlow; 49 unsigned int i, count200, badcount, nummin, nummax, diff; 50 int curmin, curmax; 51 CARD safe, oppos; 52 int valbuf[HAND_SZ], count[NUM_CARDS]; 53 bool playit[HAND_SZ]; 54 55 wmove(Score, ERR_Y, ERR_X); /* get rid of error messages */ 56 wclrtoeol(Score); 57 pp = &Player[COMP]; 58 op = &Player[PLAYER]; 59 safe = 0; 60 cango = 0; 61 canstop = FALSE; 62 foundend = FALSE; 63 64 /* Try for a Coup Forre, and see what we have. */ 65 for (i = 0; i < NUM_CARDS; i++) 66 count[i] = 0; 67 for (i = 0; i < HAND_SZ; i++) { 68 card = pp->hand[i]; 69 switch (card) { 70 case C_STOP: case C_CRASH: 71 case C_FLAT: case C_EMPTY: 72 if ((playit[i] = canplay(pp, op, card)) != 0) 73 canstop = TRUE; 74 goto norm; 75 case C_LIMIT: 76 if ((playit[i] = canplay(pp, op, card)) 77 && Numseen[C_25] == Numcards[C_25] 78 && Numseen[C_50] == Numcards[C_50]) 79 canstop = TRUE; 80 goto norm; 81 case C_25: case C_50: case C_75: 82 case C_100: case C_200: 83 if ((playit[i] = canplay(pp, op, card)) 84 && pp->mileage + Value[card] == End) 85 foundend = TRUE; 86 goto norm; 87 default: 88 playit[i] = canplay(pp, op, card); 89 norm: 90 if (playit[i]) 91 ++cango; 92 break; 93 case C_GAS_SAFE: case C_DRIVE_SAFE: 94 case C_SPARE_SAFE: case C_RIGHT_WAY: 95 if (pp->battle == opposite(card) || 96 (pp->speed == C_LIMIT && card == C_RIGHT_WAY)) { 97 Movetype = M_PLAY; 98 Card_no = i; 99 return; 100 } 101 ++safe; 102 playit[i] = TRUE; 103 break; 104 } 105 if (card >= 0) 106 ++count[card]; 107 } 108 109 /* No Coup Forre. Draw to fill hand, then restart, as needed. */ 110 if (pp->hand[0] == C_INIT && Topcard > Deck) { 111 Movetype = M_DRAW; 112 return; 113 } 114 115 #ifdef DEBUG 116 if (Debug) 117 fprintf(outf, "CALCMOVE: cango = %d, canstop = %d, safe = %d\n", 118 cango, canstop, safe); 119 #endif 120 if (foundend) 121 foundend = !check_ext(TRUE); 122 for (i = 0; safe && i < HAND_SZ; i++) { 123 if (issafety(pp->hand[i])) { 124 if (onecard(op) || (foundend && cango && !canstop)) { 125 #ifdef DEBUG 126 if (Debug) 127 fprintf(outf, 128 "CALCMOVE: onecard(op) = %d, foundend = %d\n", 129 onecard(op), foundend); 130 #endif 131 playsafe: 132 Movetype = M_PLAY; 133 Card_no = i; 134 return; 135 } 136 oppos = opposite(pp->hand[i]); 137 if (Numseen[oppos] == Numcards[oppos] && 138 !(pp->hand[i] == C_RIGHT_WAY && 139 Numseen[C_LIMIT] != Numcards[C_LIMIT])) 140 goto playsafe; 141 else if (!cango 142 && (op->can_go || !pp->can_go || Topcard < Deck)) { 143 card = (Topcard - Deck) - roll(1, 10); 144 if ((!pp->mileage) != (!op->mileage)) 145 card -= 7; 146 #ifdef DEBUG 147 if (Debug) 148 fprintf(outf, 149 "CALCMOVE: card = %d, DECK_SZ / 4 = %d\n", 150 card, DECK_SZ / 4); 151 #endif 152 if (card < DECK_SZ / 4) 153 goto playsafe; 154 } 155 safe--; 156 playit[i] = cango; 157 } 158 } 159 if (!pp->can_go && !isrepair(pp->battle)) 160 Numneed[opposite(pp->battle)]++; 161 redoit: 162 foundlow = (cango || count[C_END_LIMIT] != 0 163 || Numseen[C_LIMIT] == Numcards[C_LIMIT] 164 || pp->safety[S_RIGHT_WAY] != S_UNKNOWN); 165 foundend = FALSE; 166 count200 = pp->nummiles[C_200]; 167 badcount = 0; 168 curmax = -1; 169 curmin = 101; 170 nummin = -1; 171 nummax = -1; 172 value = valbuf; 173 for (i = 0; i < HAND_SZ; i++) { 174 card = pp->hand[i]; 175 if (issafety(card) || playit[i] == (cango != 0)) { 176 #ifdef DEBUG 177 if (Debug) 178 fprintf(outf, "CALCMOVE: switch(\"%s\")\n", 179 C_name[card]); 180 #endif 181 switch (card) { 182 case C_25: case C_50: 183 diff = End - pp->mileage; 184 /* avoid getting too close */ 185 if (Topcard > Deck && cango && diff <= 100 186 && (int)diff / Value[card] > count[card] 187 && (card == C_25 || diff % 50 == 0)) { 188 if (card == C_50 && diff - 50 == 25 189 && count[C_25] > 0) 190 goto okay; 191 *value = 0; 192 if (--cango <= 0) 193 goto redoit; 194 break; 195 } 196 okay: 197 *value = (Value[card] >> 3); 198 if (pp->speed == C_LIMIT) 199 ++*value; 200 else 201 --*value; 202 if (!foundlow 203 && (card == C_50 || count[C_50] == 0)) { 204 *value = (pp->mileage ? 10 : 20); 205 foundlow = TRUE; 206 } 207 goto miles; 208 case C_200: 209 if (++count200 > 2) { 210 *value = 0; 211 break; 212 } 213 case C_75: case C_100: 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(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 case 50: 422 case 25: 423 if (card == -1) 424 card = (End - pp->mileage == 25 ? C_25 : C_50); 425 return Numseen[card] != Numcards[card]; 426 } 427 return FALSE; 428 } 429 430 bool 431 canplay(PLAY *pp, PLAY *op, CARD card) 432 { 433 switch (card) { 434 case C_200: 435 if (pp->nummiles[C_200] == 2) 436 break; 437 /* FALLTHROUGH */ 438 case C_75: case C_100: 439 if (pp->speed == C_LIMIT) 440 break; 441 /* FALLTHROUGH */ 442 case C_50: 443 if (pp->mileage + Value[card] > End) 444 break; 445 /* FALLTHROUGH */ 446 case C_25: 447 if (pp->can_go) 448 return TRUE; 449 break; 450 case C_EMPTY: case C_FLAT: case C_CRASH: 451 case C_STOP: 452 if (op->can_go && op->safety[safety(card) - S_CONV] != S_PLAYED) 453 return TRUE; 454 break; 455 case C_LIMIT: 456 if (op->speed != C_LIMIT && 457 op->safety[S_RIGHT_WAY] != S_PLAYED && 458 op->mileage + 50 < End) 459 return TRUE; 460 break; 461 case C_GAS: case C_SPARE: case C_REPAIRS: 462 if (pp->battle == opposite(card)) 463 return TRUE; 464 break; 465 case C_GO: 466 if (!pp->can_go && 467 (isrepair(pp->battle) || pp->battle == C_STOP)) 468 return TRUE; 469 break; 470 case C_END_LIMIT: 471 if (pp->speed == C_LIMIT) 472 return TRUE; 473 } 474 return FALSE; 475 } 476