comp.c revision 1.14
1/* $NetBSD: comp.c,v 1.14 2019/02/04 03:29:41 mrg 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. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32#include <sys/cdefs.h> 33#ifndef lint 34#if 0 35static char sccsid[] = "@(#)comp.c 8.1 (Berkeley) 5/31/93"; 36#else 37__RCSID("$NetBSD: comp.c,v 1.14 2019/02/04 03:29:41 mrg 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 49void 50calcmove(void) 51{ 52 CARD card; 53 int *value; 54 PLAY *pp, *op; 55 bool foundend, canstop, foundlow; 56 int cango; 57 unsigned 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)) != 0) 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); 97norm: 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 (is_safety(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 139playsafe: 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 && !is_repair(pp->battle)) 168 Numneed[opposite(pp->battle)]++; 169redoit: 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 (is_safety(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 && (int)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 } 204okay: 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 /* FALLTHROUGH */ 222 case C_75: case C_100: 223 *value = (Value[card] >> 3); 224 if (pp->speed == C_LIMIT) 225 --*value; 226 else 227 ++*value; 228miles: 229 if (pp->mileage + Value[card] > End) 230 *value = (End == 700 ? card : 0); 231 else if (pp->mileage + Value[card] == End) { 232 *value = (foundend ? card : V_VALUABLE); 233 foundend = TRUE; 234 } 235 break; 236 case C_END_LIMIT: 237 if (pp->safety[S_RIGHT_WAY] != S_UNKNOWN) 238 *value = (pp->safety[S_RIGHT_WAY] == 239 S_PLAYED ? -1 : 1); 240 else if (pp->speed == C_LIMIT && 241 End - pp->mileage <= 50) 242 *value = 1; 243 else if (pp->speed == C_LIMIT 244 || Numseen[C_LIMIT] != Numcards[C_LIMIT]) { 245 safe = S_RIGHT_WAY; 246 oppos = C_LIMIT; 247 goto repair; 248 } 249 else { 250 *value = 0; 251 --count[C_END_LIMIT]; 252 } 253 break; 254 case C_REPAIRS: case C_SPARE: case C_GAS: 255 safe = safety(card) - S_CONV; 256 oppos = opposite(card); 257 if (pp->safety[safe] != S_UNKNOWN) 258 *value = (pp->safety[safe] == 259 S_PLAYED ? -1 : 1); 260 else if (pp->battle != oppos 261 && (Numseen[oppos] == Numcards[oppos] || 262 Numseen[oppos] + count[card] > 263 Numcards[oppos])) { 264 *value = 0; 265 --count[card]; 266 } 267 else { 268repair: 269 *value = Numcards[oppos] * 6; 270 *value += Numseen[card] - 271 Numseen[oppos]; 272 if (!cango) 273 *value /= (count[card]*count[card]); 274 count[card]--; 275 } 276 break; 277 case C_GO: 278 if (pp->safety[S_RIGHT_WAY] != S_UNKNOWN) 279 *value = (pp->safety[S_RIGHT_WAY] == 280 S_PLAYED ? -1 : 2); 281 else if (pp->can_go 282 && Numgos + count[C_GO] == Numneed[C_GO]) { 283 *value = 0; 284 --count[C_GO]; 285 } 286 else { 287 *value = Numneed[C_GO] * 3; 288 *value += (Numseen[C_GO] - Numgos); 289 *value /= (count[C_GO] * count[C_GO]); 290 count[C_GO]--; 291 } 292 break; 293 case C_LIMIT: 294 if (op->mileage + 50 >= End) { 295 *value = (End == 700 && !cango); 296 break; 297 } 298 if (canstop || (cango && !op->can_go)) 299 *value = 1; 300 else { 301 *value = (pp->safety[S_RIGHT_WAY] != 302 S_UNKNOWN ? 2 : 3); 303 safe = S_RIGHT_WAY; 304 oppos = C_END_LIMIT; 305 goto normbad; 306 } 307 break; 308 case C_CRASH: case C_EMPTY: case C_FLAT: 309 safe = safety(card) - S_CONV; 310 oppos = opposite(card); 311 *value = (pp->safety[safe]!=S_UNKNOWN ? 3 : 4); 312normbad: 313 if (op->safety[safe] == S_PLAYED) 314 *value = -1; 315 else { 316 *value *= Numneed[oppos] + 317 Numseen[oppos] + 2; 318 if (!pp->mileage || foundend || 319 onecard(op)) 320 *value += 5; 321 if (op->mileage == 0 || onecard(op)) 322 *value += 5; 323 if (op->speed == C_LIMIT) 324 *value -= 3; 325 if (cango && 326 pp->safety[safe] != S_UNKNOWN) 327 *value += 3; 328 if (!cango) 329 *value /= ++badcount; 330 } 331 break; 332 case C_STOP: 333 if (op->safety[S_RIGHT_WAY] == S_PLAYED) 334 *value = -1; 335 else { 336 *value = (pp->safety[S_RIGHT_WAY] != 337 S_UNKNOWN ? 3 : 4); 338 *value *= Numcards[C_STOP] + 339 Numseen[C_GO]; 340 if (!pp->mileage || foundend || 341 onecard(op)) 342 *value += 5; 343 if (!cango) 344 *value /= ++badcount; 345 if (op->mileage == 0) 346 *value += 5; 347 if (op->speed == C_LIMIT || !op->can_go) 348 *value -= 5; 349 if (cango && pp->safety[S_RIGHT_WAY] != 350 S_UNKNOWN) 351 *value += 5; 352 } 353 break; 354 case C_GAS_SAFE: case C_DRIVE_SAFE: 355 case C_SPARE_SAFE: case C_RIGHT_WAY: 356 *value = cango ? 0 : 101; 357 break; 358 case C_INIT: 359 *value = 0; 360 break; 361 } 362 } 363 else 364 *value = cango ? 0 : 101; 365 if (card != C_INIT) { 366 if (*value >= curmax) { 367 nummax = i; 368 curmax = *value; 369 } 370 if (*value <= curmin) { 371 nummin = i; 372 curmin = *value; 373 } 374 } 375#ifdef DEBUG 376 if (Debug) 377 mvprintw(i + 6, 2, "%3d %-14s", *value, 378 C_name[pp->hand[i]]); 379#endif 380 value++; 381 } 382 if (!pp->can_go && !is_repair(pp->battle)) 383 Numneed[opposite(pp->battle)]++; 384 if (cango) { 385play_it: 386 mvaddstr(MOVE_Y + 1, MOVE_X, "PLAY\n"); 387 Movetype = M_PLAY; 388 Card_no = nummax; 389 } 390 else { 391 if (is_safety(pp->hand[nummin])) { /* NEVER discard a safety */ 392 nummax = nummin; 393 goto play_it; 394 } 395 mvaddstr(MOVE_Y + 1, MOVE_X, "DISCARD\n"); 396 Movetype = M_DISCARD; 397 Card_no = nummin; 398 } 399 mvprintw(MOVE_Y + 2, MOVE_X, "%16s", C_name[pp->hand[Card_no]]); 400} 401 402/* 403 * Return true if the given player could conceivably win with his next card. 404 */ 405int 406onecard(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 /* FALLTHROUGH */ 429 case 50: 430 case 25: 431 if (card == -1) 432 card = (End - pp->mileage == 25 ? C_25 : C_50); 433 return Numseen[card] != Numcards[card]; 434 } 435 return FALSE; 436} 437 438int 439canplay(const PLAY *pp, const PLAY *op, CARD card) 440{ 441 switch (card) { 442 case C_200: 443 if (pp->nummiles[C_200] == 2) 444 break; 445 /* FALLTHROUGH */ 446 case C_75: case C_100: 447 if (pp->speed == C_LIMIT) 448 break; 449 /* FALLTHROUGH */ 450 case C_50: 451 if (pp->mileage + Value[card] > End) 452 break; 453 /* FALLTHROUGH */ 454 case C_25: 455 if (pp->can_go) 456 return TRUE; 457 break; 458 case C_EMPTY: case C_FLAT: case C_CRASH: 459 case C_STOP: 460 if (op->can_go && op->safety[safety(card) - S_CONV] != S_PLAYED) 461 return TRUE; 462 break; 463 case C_LIMIT: 464 if (op->speed != C_LIMIT && 465 op->safety[S_RIGHT_WAY] != S_PLAYED && 466 op->mileage + 50 < End) 467 return TRUE; 468 break; 469 case C_GAS: case C_SPARE: case C_REPAIRS: 470 if (pp->battle == opposite(card)) 471 return TRUE; 472 break; 473 case C_GO: 474 if (!pp->can_go && 475 (is_repair(pp->battle) || pp->battle == C_STOP)) 476 return TRUE; 477 break; 478 case C_END_LIMIT: 479 if (pp->speed == C_LIMIT) 480 return TRUE; 481 } 482 return FALSE; 483} 484