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