1 /* $OpenBSD: comp.c,v 1.6 2006/03/27 00:10:15 tedu Exp $ */ 2 /* $NetBSD: comp.c,v 1.4 1995/03/24 05:01:11 cgd Exp $ */ 3 4 /* 5 * Copyright (c) 1982, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 #ifndef lint 34 #if 0 35 static char sccsid[] = "@(#)comp.c 8.1 (Berkeley) 5/31/93"; 36 #else 37 static char rcsid[] = "$OpenBSD: comp.c,v 1.6 2006/03/27 00:10:15 tedu Exp $"; 38 #endif 39 #endif /* not lint */ 40 41 # include "mille.h" 42 43 /* 44 * @(#)comp.c 1.1 (Berkeley) 4/1/82 45 */ 46 47 # define V_VALUABLE 40 48 49 void 50 calcmove() 51 { 52 CARD card; 53 int *value; 54 PLAY *pp, *op; 55 bool foundend, cango, canstop, foundlow; 56 unsgn int i, count200, badcount, nummin, nummax, diff; 57 int curmin, curmax; 58 CARD safe, oppos; 59 int valbuf[HAND_SZ], count[NUM_CARDS]; 60 bool playit[HAND_SZ]; 61 62 wmove(Score, ERR_Y, ERR_X); /* get rid of error messages */ 63 wclrtoeol(Score); 64 pp = &Player[COMP]; 65 op = &Player[PLAYER]; 66 safe = 0; 67 cango = 0; 68 canstop = FALSE; 69 foundend = FALSE; 70 71 /* Try for a Coup Forre, and see what we have. */ 72 for (i = 0; i < NUM_CARDS; i++) 73 count[i] = 0; 74 for (i = 0; i < HAND_SZ; i++) { 75 card = pp->hand[i]; 76 switch (card) { 77 case C_STOP: case C_CRASH: 78 case C_FLAT: case C_EMPTY: 79 if ((playit[i] = canplay(pp, op, card))) 80 canstop = TRUE; 81 goto norm; 82 case C_LIMIT: 83 if ((playit[i] = canplay(pp, op, card)) 84 && Numseen[C_25] == Numcards[C_25] 85 && Numseen[C_50] == Numcards[C_50]) 86 canstop = TRUE; 87 goto norm; 88 case C_25: case C_50: case C_75: 89 case C_100: case C_200: 90 if ((playit[i] = canplay(pp, op, card)) 91 && pp->mileage + Value[card] == End) 92 foundend = TRUE; 93 goto norm; 94 default: 95 playit[i] = canplay(pp, op, card); 96 norm: 97 if (playit[i]) 98 ++cango; 99 break; 100 case C_GAS_SAFE: case C_DRIVE_SAFE: 101 case C_SPARE_SAFE: case C_RIGHT_WAY: 102 if (pp->battle == opposite(card) || 103 (pp->speed == C_LIMIT && card == C_RIGHT_WAY)) { 104 Movetype = M_PLAY; 105 Card_no = i; 106 return; 107 } 108 ++safe; 109 playit[i] = TRUE; 110 break; 111 } 112 if (card >= 0) 113 ++count[card]; 114 } 115 116 /* No Coup Forre. Draw to fill hand, then restart, as needed. */ 117 if (pp->hand[0] == C_INIT && Topcard > Deck) { 118 Movetype = M_DRAW; 119 return; 120 } 121 122 #ifdef DEBUG 123 if (Debug) 124 fprintf(outf, "CALCMOVE: cango = %d, canstop = %d, safe = %d\n", 125 cango, canstop, safe); 126 #endif 127 if (foundend) 128 foundend = !check_ext(TRUE); 129 for (i = 0; safe && i < HAND_SZ; i++) { 130 if (is_safety(pp->hand[i])) { 131 if (onecard(op) || (foundend && cango && !canstop)) { 132 #ifdef DEBUG 133 if (Debug) 134 fprintf(outf, 135 "CALCMOVE: onecard(op) = %d, foundend = %d\n", 136 onecard(op), foundend); 137 #endif 138 playsafe: 139 Movetype = M_PLAY; 140 Card_no = i; 141 return; 142 } 143 oppos = opposite(pp->hand[i]); 144 if (Numseen[oppos] == Numcards[oppos] && 145 !(pp->hand[i] == C_RIGHT_WAY && 146 Numseen[C_LIMIT] != Numcards[C_LIMIT])) 147 goto playsafe; 148 else if (!cango 149 && (op->can_go || !pp->can_go || Topcard < Deck)) { 150 card = (Topcard - Deck) - roll(1, 10); 151 if ((!pp->mileage) != (!op->mileage)) 152 card -= 7; 153 #ifdef DEBUG 154 if (Debug) 155 fprintf(outf, 156 "CALCMOVE: card = %d, DECK_SZ / 4 = %d\n", 157 card, DECK_SZ / 4); 158 #endif 159 if (card < DECK_SZ / 4) 160 goto playsafe; 161 } 162 safe--; 163 playit[i] = cango; 164 } 165 } 166 if (!pp->can_go && !is_repair(pp->battle)) 167 Numneed[opposite(pp->battle)]++; 168 redoit: 169 foundlow = (cango || count[C_END_LIMIT] != 0 170 || Numseen[C_LIMIT] == Numcards[C_LIMIT] 171 || pp->safety[S_RIGHT_WAY] != S_UNKNOWN); 172 foundend = FALSE; 173 count200 = pp->nummiles[C_200]; 174 badcount = 0; 175 curmax = -1; 176 curmin = 101; 177 nummin = -1; 178 nummax = -1; 179 value = valbuf; 180 for (i = 0; i < HAND_SZ; i++) { 181 card = pp->hand[i]; 182 if (is_safety(card) || playit[i] == (cango != 0)) { 183 #ifdef DEBUG 184 if (Debug) 185 fprintf(outf, "CALCMOVE: switch(\"%s\")\n", 186 C_name[card]); 187 #endif 188 switch (card) { 189 case C_25: case C_50: 190 diff = End - pp->mileage; 191 /* avoid getting too close */ 192 if (Topcard > Deck && cango && diff <= 100 193 && diff / Value[card] > count[card] 194 && (card == C_25 || diff % 50 == 0)) { 195 if (card == C_50 && diff - 50 == 25 196 && count[C_25] > 0) 197 goto okay; 198 *value = 0; 199 if (--cango <= 0) 200 goto redoit; 201 break; 202 } 203 okay: 204 *value = (Value[card] >> 3); 205 if (pp->speed == C_LIMIT) 206 ++*value; 207 else 208 --*value; 209 if (!foundlow 210 && (card == C_50 || count[C_50] == 0)) { 211 *value = (pp->mileage ? 10 : 20); 212 foundlow = TRUE; 213 } 214 goto miles; 215 case C_200: 216 if (++count200 > 2) { 217 *value = 0; 218 break; 219 } 220 case C_75: case C_100: 221 *value = (Value[card] >> 3); 222 if (pp->speed == C_LIMIT) 223 --*value; 224 else 225 ++*value; 226 miles: 227 if (pp->mileage + Value[card] > End) 228 *value = (End == 700 ? card : 0); 229 else if (pp->mileage + Value[card] == End) { 230 *value = (foundend ? card : V_VALUABLE); 231 foundend = TRUE; 232 } 233 break; 234 case C_END_LIMIT: 235 if (pp->safety[S_RIGHT_WAY] != S_UNKNOWN) 236 *value = (pp->safety[S_RIGHT_WAY] == 237 S_PLAYED ? -1 : 1); 238 else if (pp->speed == C_LIMIT && 239 End - pp->mileage <= 50) 240 *value = 1; 241 else if (pp->speed == C_LIMIT 242 || Numseen[C_LIMIT] != Numcards[C_LIMIT]) { 243 safe = S_RIGHT_WAY; 244 oppos = C_LIMIT; 245 goto repair; 246 } 247 else { 248 *value = 0; 249 --count[C_END_LIMIT]; 250 } 251 break; 252 case C_REPAIRS: case C_SPARE: case C_GAS: 253 safe = safety(card) - S_CONV; 254 oppos = opposite(card); 255 if (pp->safety[safe] != S_UNKNOWN) 256 *value = (pp->safety[safe] == 257 S_PLAYED ? -1 : 1); 258 else if (pp->battle != oppos 259 && (Numseen[oppos] == Numcards[oppos] || 260 Numseen[oppos] + count[card] > 261 Numcards[oppos])) { 262 *value = 0; 263 --count[card]; 264 } 265 else { 266 repair: 267 *value = Numcards[oppos] * 6; 268 *value += Numseen[card] - 269 Numseen[oppos]; 270 if (!cango) 271 *value /= (count[card]*count[card]); 272 count[card]--; 273 } 274 break; 275 case C_GO: 276 if (pp->safety[S_RIGHT_WAY] != S_UNKNOWN) 277 *value = (pp->safety[S_RIGHT_WAY] == 278 S_PLAYED ? -1 : 2); 279 else if (pp->can_go 280 && Numgos + count[C_GO] == Numneed[C_GO]) { 281 *value = 0; 282 --count[C_GO]; 283 } 284 else { 285 *value = Numneed[C_GO] * 3; 286 *value += (Numseen[C_GO] - Numgos); 287 *value /= (count[C_GO] * count[C_GO]); 288 count[C_GO]--; 289 } 290 break; 291 case C_LIMIT: 292 if (op->mileage + 50 >= End) { 293 *value = (End == 700 && !cango); 294 break; 295 } 296 if (canstop || (cango && !op->can_go)) 297 *value = 1; 298 else { 299 *value = (pp->safety[S_RIGHT_WAY] != 300 S_UNKNOWN ? 2 : 3); 301 safe = S_RIGHT_WAY; 302 oppos = C_END_LIMIT; 303 goto normbad; 304 } 305 break; 306 case C_CRASH: case C_EMPTY: case C_FLAT: 307 safe = safety(card) - S_CONV; 308 oppos = opposite(card); 309 *value = (pp->safety[safe]!=S_UNKNOWN ? 3 : 4); 310 normbad: 311 if (op->safety[safe] == S_PLAYED) 312 *value = -1; 313 else { 314 *value *= Numneed[oppos] + 315 Numseen[oppos] + 2; 316 if (!pp->mileage || foundend || 317 onecard(op)) 318 *value += 5; 319 if (op->mileage == 0 || onecard(op)) 320 *value += 5; 321 if (op->speed == C_LIMIT) 322 *value -= 3; 323 if (cango && 324 pp->safety[safe] != S_UNKNOWN) 325 *value += 3; 326 if (!cango) 327 *value /= ++badcount; 328 } 329 break; 330 case C_STOP: 331 if (op->safety[S_RIGHT_WAY] == S_PLAYED) 332 *value = -1; 333 else { 334 *value = (pp->safety[S_RIGHT_WAY] != 335 S_UNKNOWN ? 3 : 4); 336 *value *= Numcards[C_STOP] + 337 Numseen[C_GO]; 338 if (!pp->mileage || foundend || 339 onecard(op)) 340 *value += 5; 341 if (!cango) 342 *value /= ++badcount; 343 if (op->mileage == 0) 344 *value += 5; 345 if ((op->speed == C_LIMIT) || 346 !op->can_go) 347 *value -= 5; 348 if (cango && pp->safety[S_RIGHT_WAY] != 349 S_UNKNOWN) 350 *value += 5; 351 } 352 break; 353 case C_GAS_SAFE: case C_DRIVE_SAFE: 354 case C_SPARE_SAFE: case C_RIGHT_WAY: 355 *value = cango ? 0 : 101; 356 break; 357 case C_INIT: 358 *value = 0; 359 break; 360 } 361 } 362 else 363 *value = cango ? 0 : 101; 364 if (card != C_INIT) { 365 if (*value >= curmax) { 366 nummax = i; 367 curmax = *value; 368 } 369 if (*value <= curmin) { 370 nummin = i; 371 curmin = *value; 372 } 373 } 374 #ifdef DEBUG 375 if (Debug) 376 mvprintw(i + 6, 2, "%3d %-14s", *value, 377 C_name[pp->hand[i]]); 378 #endif 379 value++; 380 } 381 if (!pp->can_go && !is_repair(pp->battle)) 382 Numneed[opposite(pp->battle)]++; 383 if (cango) { 384 play_it: 385 mvaddstr(MOVE_Y + 1, MOVE_X, "PLAY\n"); 386 Movetype = M_PLAY; 387 Card_no = nummax; 388 } 389 else { 390 if (is_safety(pp->hand[nummin])) { /* NEVER discard a safety */ 391 nummax = nummin; 392 goto play_it; 393 } 394 mvaddstr(MOVE_Y + 1, MOVE_X, "DISCARD\n"); 395 Movetype = M_DISCARD; 396 Card_no = nummin; 397 } 398 mvprintw(MOVE_Y + 2, MOVE_X, "%16s", C_name[pp->hand[Card_no]]); 399 } 400 401 /* 402 * Return true if the given player could conceivably win with his next card. 403 */ 404 int 405 onecard(pp) 406 const PLAY *pp; 407 { 408 CARD bat, spd, card; 409 410 bat = pp->battle; 411 spd = pp->speed; 412 card = -1; 413 if (pp->can_go || ((is_repair(bat) || bat == C_STOP || spd == C_LIMIT) && 414 Numseen[S_RIGHT_WAY] != 0) || 415 (bat >= 0 && Numseen[safety(bat)] != 0)) 416 switch (End - pp->mileage) { 417 case 200: 418 if (pp->nummiles[C_200] == 2) 419 return FALSE; 420 card = C_200; 421 /* FALLTHROUGH */ 422 case 100: 423 case 75: 424 if (card == -1) 425 card = (End - pp->mileage == 75 ? C_75 : C_100); 426 if (spd == C_LIMIT) 427 return Numseen[S_RIGHT_WAY] == 0; 428 case 50: 429 case 25: 430 if (card == -1) 431 card = (End - pp->mileage == 25 ? C_25 : C_50); 432 return Numseen[card] != Numcards[card]; 433 } 434 return FALSE; 435 } 436 437 int 438 canplay(pp, op, card) 439 const PLAY *pp, *op; 440 CARD card; 441 { 442 switch (card) { 443 case C_200: 444 if (pp->nummiles[C_200] == 2) 445 break; 446 /* FALLTHROUGH */ 447 case C_75: case C_100: 448 if (pp->speed == C_LIMIT) 449 break; 450 /* FALLTHROUGH */ 451 case C_50: 452 if (pp->mileage + Value[card] > End) 453 break; 454 /* FALLTHROUGH */ 455 case C_25: 456 if (pp->can_go) 457 return TRUE; 458 break; 459 case C_EMPTY: case C_FLAT: case C_CRASH: 460 case C_STOP: 461 if (op->can_go && op->safety[safety(card) - S_CONV] != S_PLAYED) 462 return TRUE; 463 break; 464 case C_LIMIT: 465 if (op->speed != C_LIMIT && 466 op->safety[S_RIGHT_WAY] != S_PLAYED && 467 op->mileage + 50 < End) 468 return TRUE; 469 break; 470 case C_GAS: case C_SPARE: case C_REPAIRS: 471 if (pp->battle == opposite(card)) 472 return TRUE; 473 break; 474 case C_GO: 475 if (!pp->can_go && 476 (is_repair(pp->battle) || pp->battle == C_STOP)) 477 return TRUE; 478 break; 479 case C_END_LIMIT: 480 if (pp->speed == C_LIMIT) 481 return TRUE; 482 } 483 return FALSE; 484 } 485