comp.c revision 1.4
1/* $NetBSD: comp.c,v 1.4 1995/03/24 05:01:11 cgd 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#ifndef lint 37#if 0 38static char sccsid[] = "@(#)comp.c 8.1 (Berkeley) 5/31/93"; 39#else 40static char rcsid[] = "$NetBSD: comp.c,v 1.4 1995/03/24 05:01:11 cgd Exp $"; 41#endif 42#endif /* not lint */ 43 44# include "mille.h" 45 46/* 47 * @(#)comp.c 1.1 (Berkeley) 4/1/82 48 */ 49 50# define V_VALUABLE 40 51 52calcmove() 53{ 54 register CARD card; 55 register int *value; 56 register PLAY *pp, *op; 57 register bool foundend, cango, canstop, foundlow; 58 register unsgn int i, count200, badcount, nummin, nummax, diff; 59 register int curmin, curmax; 60 register CARD safe, oppos; 61 int valbuf[HAND_SZ], count[NUM_CARDS]; 62 bool playit[HAND_SZ]; 63 64 wmove(Score, ERR_Y, ERR_X); /* get rid of error messages */ 65 wclrtoeol(Score); 66 pp = &Player[COMP]; 67 op = &Player[PLAYER]; 68 safe = 0; 69 cango = 0; 70 canstop = FALSE; 71 foundend = FALSE; 72 73 /* Try for a Coup Forre, and see what we have. */ 74 for (i = 0; i < NUM_CARDS; i++) 75 count[i] = 0; 76 for (i = 0; i < HAND_SZ; i++) { 77 card = pp->hand[i]; 78 switch (card) { 79 case C_STOP: case C_CRASH: 80 case C_FLAT: case C_EMPTY: 81 if (playit[i] = canplay(pp, op, card)) 82 canstop = TRUE; 83 goto norm; 84 case C_LIMIT: 85 if ((playit[i] = canplay(pp, op, card)) 86 && Numseen[C_25] == Numcards[C_25] 87 && Numseen[C_50] == Numcards[C_50]) 88 canstop = TRUE; 89 goto norm; 90 case C_25: case C_50: case C_75: 91 case C_100: case C_200: 92 if ((playit[i] = canplay(pp, op, card)) 93 && pp->mileage + Value[card] == End) 94 foundend = TRUE; 95 goto norm; 96 default: 97 playit[i] = canplay(pp, op, card); 98norm: 99 if (playit[i]) 100 ++cango; 101 break; 102 case C_GAS_SAFE: case C_DRIVE_SAFE: 103 case C_SPARE_SAFE: case C_RIGHT_WAY: 104 if (pp->battle == opposite(card) || 105 (pp->speed == C_LIMIT && card == C_RIGHT_WAY)) { 106 Movetype = M_PLAY; 107 Card_no = i; 108 return; 109 } 110 ++safe; 111 playit[i] = TRUE; 112 break; 113 } 114 if (card >= 0) 115 ++count[card]; 116 } 117 118 /* No Coup Forre. Draw to fill hand, then restart, as needed. */ 119 if (pp->hand[0] == C_INIT && Topcard > Deck) { 120 Movetype = M_DRAW; 121 return; 122 } 123 124#ifdef DEBUG 125 if (Debug) 126 fprintf(outf, "CALCMOVE: cango = %d, canstop = %d, safe = %d\n", 127 cango, canstop, safe); 128#endif 129 if (foundend) 130 foundend = !check_ext(TRUE); 131 for (i = 0; safe && i < HAND_SZ; i++) { 132 if (issafety(pp->hand[i])) { 133 if (onecard(op) || (foundend && cango && !canstop)) { 134#ifdef DEBUG 135 if (Debug) 136 fprintf(outf, 137 "CALCMOVE: onecard(op) = %d, foundend = %d\n", 138 onecard(op), foundend); 139#endif 140playsafe: 141 Movetype = M_PLAY; 142 Card_no = i; 143 return; 144 } 145 oppos = opposite(pp->hand[i]); 146 if (Numseen[oppos] == Numcards[oppos] && 147 !(pp->hand[i] == C_RIGHT_WAY && 148 Numseen[C_LIMIT] != Numcards[C_LIMIT])) 149 goto playsafe; 150 else if (!cango 151 && (op->can_go || !pp->can_go || Topcard < Deck)) { 152 card = (Topcard - Deck) - roll(1, 10); 153 if ((!pp->mileage) != (!op->mileage)) 154 card -= 7; 155#ifdef DEBUG 156 if (Debug) 157 fprintf(outf, 158 "CALCMOVE: card = %d, DECK_SZ / 4 = %d\n", 159 card, DECK_SZ / 4); 160#endif 161 if (card < DECK_SZ / 4) 162 goto playsafe; 163 } 164 safe--; 165 playit[i] = cango; 166 } 167 } 168 if (!pp->can_go && !isrepair(pp->battle)) 169 Numneed[opposite(pp->battle)]++; 170redoit: 171 foundlow = (cango || count[C_END_LIMIT] != 0 172 || Numseen[C_LIMIT] == Numcards[C_LIMIT] 173 || pp->safety[S_RIGHT_WAY] != S_UNKNOWN); 174 foundend = FALSE; 175 count200 = pp->nummiles[C_200]; 176 badcount = 0; 177 curmax = -1; 178 curmin = 101; 179 nummin = -1; 180 nummax = -1; 181 value = valbuf; 182 for (i = 0; i < HAND_SZ; i++) { 183 card = pp->hand[i]; 184 if (issafety(card) || playit[i] == (cango != 0)) { 185#ifdef DEBUG 186 if (Debug) 187 fprintf(outf, "CALCMOVE: switch(\"%s\")\n", 188 C_name[card]); 189#endif 190 switch (card) { 191 case C_25: case C_50: 192 diff = End - pp->mileage; 193 /* avoid getting too close */ 194 if (Topcard > Deck && cango && diff <= 100 195 && diff / Value[card] > count[card] 196 && (card == C_25 || diff % 50 == 0)) { 197 if (card == C_50 && diff - 50 == 25 198 && count[C_25] > 0) 199 goto okay; 200 *value = 0; 201 if (--cango <= 0) 202 goto redoit; 203 break; 204 } 205okay: 206 *value = (Value[card] >> 3); 207 if (pp->speed == C_LIMIT) 208 ++*value; 209 else 210 --*value; 211 if (!foundlow 212 && (card == C_50 || count[C_50] == 0)) { 213 *value = (pp->mileage ? 10 : 20); 214 foundlow = TRUE; 215 } 216 goto miles; 217 case C_200: 218 if (++count200 > 2) { 219 *value = 0; 220 break; 221 } 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 ((card == C_LIMIT && 348 op->speed == C_LIMIT) || 349 !op->can_go) 350 *value -= 5; 351 if (cango && pp->safety[S_RIGHT_WAY] != 352 S_UNKNOWN) 353 *value += 5; 354 } 355 break; 356 case C_GAS_SAFE: case C_DRIVE_SAFE: 357 case C_SPARE_SAFE: case C_RIGHT_WAY: 358 *value = cango ? 0 : 101; 359 break; 360 case C_INIT: 361 *value = 0; 362 break; 363 } 364 } 365 else 366 *value = cango ? 0 : 101; 367 if (card != C_INIT) { 368 if (*value >= curmax) { 369 nummax = i; 370 curmax = *value; 371 } 372 if (*value <= curmin) { 373 nummin = i; 374 curmin = *value; 375 } 376 } 377#ifdef DEBUG 378 if (Debug) 379 mvprintw(i + 6, 2, "%3d %-14s", *value, 380 C_name[pp->hand[i]]); 381#endif 382 value++; 383 } 384 if (!pp->can_go && !isrepair(pp->battle)) 385 Numneed[opposite(pp->battle)]++; 386 if (cango) { 387play_it: 388 mvaddstr(MOVE_Y + 1, MOVE_X, "PLAY\n"); 389 Movetype = M_PLAY; 390 Card_no = nummax; 391 } 392 else { 393 if (issafety(pp->hand[nummin])) { /* NEVER discard a safety */ 394 nummax = nummin; 395 goto play_it; 396 } 397 mvaddstr(MOVE_Y + 1, MOVE_X, "DISCARD\n"); 398 Movetype = M_DISCARD; 399 Card_no = nummin; 400 } 401 mvprintw(MOVE_Y + 2, MOVE_X, "%16s", C_name[pp->hand[Card_no]]); 402} 403 404/* 405 * Return true if the given player could conceivably win with his next card. 406 */ 407onecard(pp) 408register PLAY *pp; 409{ 410 register CARD bat, spd, card; 411 412 bat = pp->battle; 413 spd = pp->speed; 414 card = -1; 415 if (pp->can_go || ((isrepair(bat) || bat == C_STOP || spd == C_LIMIT) && 416 Numseen[S_RIGHT_WAY] != 0) || 417 bat >= 0 && Numseen[safety(bat)] != 0) 418 switch (End - pp->mileage) { 419 case 200: 420 if (pp->nummiles[C_200] == 2) 421 return FALSE; 422 card = C_200; 423 /* FALLTHROUGH */ 424 case 100: 425 case 75: 426 if (card == -1) 427 card = (End - pp->mileage == 75 ? C_75 : C_100); 428 if (spd == C_LIMIT) 429 return Numseen[S_RIGHT_WAY] == 0; 430 case 50: 431 case 25: 432 if (card == -1) 433 card = (End - pp->mileage == 25 ? C_25 : C_50); 434 return Numseen[card] != Numcards[card]; 435 } 436 return FALSE; 437} 438 439canplay(pp, op, card) 440register PLAY *pp, *op; 441register CARD card; 442{ 443 switch (card) { 444 case C_200: 445 if (pp->nummiles[C_200] == 2) 446 break; 447 /* FALLTHROUGH */ 448 case C_75: case C_100: 449 if (pp->speed == C_LIMIT) 450 break; 451 /* FALLTHROUGH */ 452 case C_50: 453 if (pp->mileage + Value[card] > End) 454 break; 455 /* FALLTHROUGH */ 456 case C_25: 457 if (pp->can_go) 458 return TRUE; 459 break; 460 case C_EMPTY: case C_FLAT: case C_CRASH: 461 case C_STOP: 462 if (op->can_go && op->safety[safety(card) - S_CONV] != S_PLAYED) 463 return TRUE; 464 break; 465 case C_LIMIT: 466 if (op->speed != C_LIMIT && 467 op->safety[S_RIGHT_WAY] != S_PLAYED && 468 op->mileage + 50 < End) 469 return TRUE; 470 break; 471 case C_GAS: case C_SPARE: case C_REPAIRS: 472 if (pp->battle == opposite(card)) 473 return TRUE; 474 break; 475 case C_GO: 476 if (!pp->can_go && 477 (isrepair(pp->battle) || pp->battle == C_STOP)) 478 return TRUE; 479 break; 480 case C_END_LIMIT: 481 if (pp->speed == C_LIMIT) 482 return TRUE; 483 } 484 return FALSE; 485} 486