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