1 /* $OpenBSD: comp.c,v 1.10 2016/01/08 18:09:59 mestre 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 #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 = 0; 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; 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 (is_safety(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 && !is_repair(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 (is_safety(card) || playit[i] == (cango != 0)) { 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 && 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 if (--cango <= 0) 192 goto redoit; 193 break; 194 } 195 okay: 196 *value = (Value[card] >> 3); 197 if (pp->speed == C_LIMIT) 198 ++*value; 199 else 200 --*value; 201 if (!foundlow 202 && (card == C_50 || count[C_50] == 0)) { 203 *value = (pp->mileage ? 10 : 20); 204 foundlow = TRUE; 205 } 206 goto miles; 207 case C_200: 208 if (++count200 > 2) { 209 *value = 0; 210 break; 211 } 212 case C_75: case C_100: 213 *value = (Value[card] >> 3); 214 if (pp->speed == C_LIMIT) 215 --*value; 216 else 217 ++*value; 218 miles: 219 if (pp->mileage + Value[card] > End) 220 *value = (End == 700 ? card : 0); 221 else if (pp->mileage + Value[card] == End) { 222 *value = (foundend ? card : V_VALUABLE); 223 foundend = TRUE; 224 } 225 break; 226 case C_END_LIMIT: 227 if (pp->safety[S_RIGHT_WAY] != S_UNKNOWN) 228 *value = (pp->safety[S_RIGHT_WAY] == 229 S_PLAYED ? -1 : 1); 230 else if (pp->speed == C_LIMIT && 231 End - pp->mileage <= 50) 232 *value = 1; 233 else if (pp->speed == C_LIMIT 234 || Numseen[C_LIMIT] != Numcards[C_LIMIT]) { 235 safe = S_RIGHT_WAY; 236 oppos = C_LIMIT; 237 goto repair; 238 } 239 else { 240 *value = 0; 241 --count[C_END_LIMIT]; 242 } 243 break; 244 case C_REPAIRS: case C_SPARE: case C_GAS: 245 safe = safety(card) - S_CONV; 246 oppos = opposite(card); 247 if (pp->safety[safe] != S_UNKNOWN) 248 *value = (pp->safety[safe] == 249 S_PLAYED ? -1 : 1); 250 else if (pp->battle != oppos 251 && (Numseen[oppos] == Numcards[oppos] || 252 Numseen[oppos] + count[card] > 253 Numcards[oppos])) { 254 *value = 0; 255 --count[card]; 256 } 257 else { 258 repair: 259 *value = Numcards[oppos] * 6; 260 *value += Numseen[card] - 261 Numseen[oppos]; 262 if (!cango) 263 *value /= (count[card]*count[card]); 264 count[card]--; 265 } 266 break; 267 case C_GO: 268 if (pp->safety[S_RIGHT_WAY] != S_UNKNOWN) 269 *value = (pp->safety[S_RIGHT_WAY] == 270 S_PLAYED ? -1 : 2); 271 else if (pp->can_go 272 && Numgos + count[C_GO] == Numneed[C_GO]) { 273 *value = 0; 274 --count[C_GO]; 275 } 276 else { 277 *value = Numneed[C_GO] * 3; 278 *value += (Numseen[C_GO] - Numgos); 279 *value /= (count[C_GO] * count[C_GO]); 280 count[C_GO]--; 281 } 282 break; 283 case C_LIMIT: 284 if (op->mileage + 50 >= End) { 285 *value = (End == 700 && !cango); 286 break; 287 } 288 if (canstop || (cango && !op->can_go)) 289 *value = 1; 290 else { 291 *value = (pp->safety[S_RIGHT_WAY] != 292 S_UNKNOWN ? 2 : 3); 293 safe = S_RIGHT_WAY; 294 oppos = C_END_LIMIT; 295 goto normbad; 296 } 297 break; 298 case C_CRASH: case C_EMPTY: case C_FLAT: 299 safe = safety(card) - S_CONV; 300 oppos = opposite(card); 301 *value = (pp->safety[safe]!=S_UNKNOWN ? 3 : 4); 302 normbad: 303 if (op->safety[safe] == S_PLAYED) 304 *value = -1; 305 else { 306 *value *= Numneed[oppos] + 307 Numseen[oppos] + 2; 308 if (!pp->mileage || foundend || 309 onecard(op)) 310 *value += 5; 311 if (op->mileage == 0 || onecard(op)) 312 *value += 5; 313 if (op->speed == C_LIMIT) 314 *value -= 3; 315 if (cango && 316 pp->safety[safe] != S_UNKNOWN) 317 *value += 3; 318 if (!cango) 319 *value /= ++badcount; 320 } 321 break; 322 case C_STOP: 323 if (op->safety[S_RIGHT_WAY] == S_PLAYED) 324 *value = -1; 325 else { 326 *value = (pp->safety[S_RIGHT_WAY] != 327 S_UNKNOWN ? 3 : 4); 328 *value *= Numcards[C_STOP] + 329 Numseen[C_GO]; 330 if (!pp->mileage || foundend || 331 onecard(op)) 332 *value += 5; 333 if (!cango) 334 *value /= ++badcount; 335 if (op->mileage == 0) 336 *value += 5; 337 if ((op->speed == C_LIMIT) || 338 !op->can_go) 339 *value -= 5; 340 if (cango && pp->safety[S_RIGHT_WAY] != 341 S_UNKNOWN) 342 *value += 5; 343 } 344 break; 345 case C_GAS_SAFE: case C_DRIVE_SAFE: 346 case C_SPARE_SAFE: case C_RIGHT_WAY: 347 *value = cango ? 0 : 101; 348 break; 349 case C_INIT: 350 *value = 0; 351 break; 352 } 353 } 354 else 355 *value = cango ? 0 : 101; 356 if (card != C_INIT) { 357 if (*value >= curmax) { 358 nummax = i; 359 curmax = *value; 360 } 361 if (*value <= curmin) { 362 nummin = i; 363 curmin = *value; 364 } 365 } 366 #ifdef DEBUG 367 if (Debug) 368 mvprintw(i + 6, 2, "%3d %-14s", *value, 369 C_name[pp->hand[i]]); 370 #endif 371 value++; 372 } 373 if (!pp->can_go && !is_repair(pp->battle)) 374 Numneed[opposite(pp->battle)]++; 375 if (cango) { 376 play_it: 377 mvaddstr(MOVE_Y + 1, MOVE_X, "PLAY\n"); 378 Movetype = M_PLAY; 379 Card_no = nummax; 380 } 381 else { 382 if (is_safety(pp->hand[nummin])) { /* NEVER discard a safety */ 383 nummax = nummin; 384 goto play_it; 385 } 386 mvaddstr(MOVE_Y + 1, MOVE_X, "DISCARD\n"); 387 Movetype = M_DISCARD; 388 Card_no = nummin; 389 } 390 mvprintw(MOVE_Y + 2, MOVE_X, "%16s", C_name[pp->hand[Card_no]]); 391 } 392 393 /* 394 * Return true if the given player could conceivably win with his next card. 395 */ 396 int 397 onecard(const PLAY *pp) 398 { 399 CARD bat, spd, card; 400 401 bat = pp->battle; 402 spd = pp->speed; 403 card = -1; 404 if (pp->can_go || ((is_repair(bat) || bat == C_STOP || spd == C_LIMIT) && 405 Numseen[S_RIGHT_WAY] != 0) || 406 (bat >= 0 && Numseen[safety(bat)] != 0)) 407 switch (End - pp->mileage) { 408 case 200: 409 if (pp->nummiles[C_200] == 2) 410 return FALSE; 411 card = C_200; 412 /* FALLTHROUGH */ 413 case 100: 414 case 75: 415 if (card == -1) 416 card = (End - pp->mileage == 75 ? C_75 : C_100); 417 if (spd == C_LIMIT) 418 return Numseen[S_RIGHT_WAY] == 0; 419 case 50: 420 case 25: 421 if (card == -1) 422 card = (End - pp->mileage == 25 ? C_25 : C_50); 423 return Numseen[card] != Numcards[card]; 424 } 425 return FALSE; 426 } 427 428 int 429 canplay(const PLAY *pp, const PLAY *op, CARD card) 430 { 431 switch (card) { 432 case C_200: 433 if (pp->nummiles[C_200] == 2) 434 break; 435 /* FALLTHROUGH */ 436 case C_75: case C_100: 437 if (pp->speed == C_LIMIT) 438 break; 439 /* FALLTHROUGH */ 440 case C_50: 441 if (pp->mileage + Value[card] > End) 442 break; 443 /* FALLTHROUGH */ 444 case C_25: 445 if (pp->can_go) 446 return TRUE; 447 break; 448 case C_EMPTY: case C_FLAT: case C_CRASH: 449 case C_STOP: 450 if (op->can_go && op->safety[safety(card) - S_CONV] != S_PLAYED) 451 return TRUE; 452 break; 453 case C_LIMIT: 454 if (op->speed != C_LIMIT && 455 op->safety[S_RIGHT_WAY] != S_PLAYED && 456 op->mileage + 50 < End) 457 return TRUE; 458 break; 459 case C_GAS: case C_SPARE: case C_REPAIRS: 460 if (pp->battle == opposite(card)) 461 return TRUE; 462 break; 463 case C_GO: 464 if (!pp->can_go && 465 (is_repair(pp->battle) || pp->battle == C_STOP)) 466 return TRUE; 467 break; 468 case C_END_LIMIT: 469 if (pp->speed == C_LIMIT) 470 return TRUE; 471 } 472 return FALSE; 473 } 474