comp.c revision 1.10
1/* $NetBSD: comp.c,v 1.10 2006/03/19 00:29:27 christos 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.10 2006/03/19 00:29:27 christos 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() 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)) != 0) 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); 96norm: 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 138playsafe: 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)]++; 168redoit: 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 && (int)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 } 203okay: 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; 226miles: 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 { 266repair: 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); 310normbad: 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 || !op->can_go) 346 *value -= 5; 347 if (cango && pp->safety[S_RIGHT_WAY] != 348 S_UNKNOWN) 349 *value += 5; 350 } 351 break; 352 case C_GAS_SAFE: case C_DRIVE_SAFE: 353 case C_SPARE_SAFE: case C_RIGHT_WAY: 354 *value = cango ? 0 : 101; 355 break; 356 case C_INIT: 357 *value = 0; 358 break; 359 } 360 } 361 else 362 *value = cango ? 0 : 101; 363 if (card != C_INIT) { 364 if (*value >= curmax) { 365 nummax = i; 366 curmax = *value; 367 } 368 if (*value <= curmin) { 369 nummin = i; 370 curmin = *value; 371 } 372 } 373#ifdef DEBUG 374 if (Debug) 375 mvprintw(i + 6, 2, "%3d %-14s", *value, 376 C_name[pp->hand[i]]); 377#endif 378 value++; 379 } 380 if (!pp->can_go && !is_repair(pp->battle)) 381 Numneed[opposite(pp->battle)]++; 382 if (cango) { 383play_it: 384 mvaddstr(MOVE_Y + 1, MOVE_X, "PLAY\n"); 385 Movetype = M_PLAY; 386 Card_no = nummax; 387 } 388 else { 389 if (is_safety(pp->hand[nummin])) { /* NEVER discard a safety */ 390 nummax = nummin; 391 goto play_it; 392 } 393 mvaddstr(MOVE_Y + 1, MOVE_X, "DISCARD\n"); 394 Movetype = M_DISCARD; 395 Card_no = nummin; 396 } 397 mvprintw(MOVE_Y + 2, MOVE_X, "%16s", C_name[pp->hand[Card_no]]); 398} 399 400/* 401 * Return true if the given player could conceivably win with his next card. 402 */ 403int 404onecard(pp) 405 const PLAY *pp; 406{ 407 CARD bat, spd, card; 408 409 bat = pp->battle; 410 spd = pp->speed; 411 card = -1; 412 if (pp->can_go || ((is_repair(bat) || bat == C_STOP || spd == C_LIMIT) && 413 Numseen[S_RIGHT_WAY] != 0) || 414 (bat >= 0 && Numseen[safety(bat)] != 0)) 415 switch (End - pp->mileage) { 416 case 200: 417 if (pp->nummiles[C_200] == 2) 418 return FALSE; 419 card = C_200; 420 /* FALLTHROUGH */ 421 case 100: 422 case 75: 423 if (card == -1) 424 card = (End - pp->mileage == 75 ? C_75 : C_100); 425 if (spd == C_LIMIT) 426 return Numseen[S_RIGHT_WAY] == 0; 427 case 50: 428 case 25: 429 if (card == -1) 430 card = (End - pp->mileage == 25 ? C_25 : C_50); 431 return Numseen[card] != Numcards[card]; 432 } 433 return FALSE; 434} 435 436int 437canplay(pp, op, card) 438 const PLAY *pp, *op; 439 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