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