1 /* 2 * Copyright (c) 1982, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char sccsid[] = "@(#)comp.c 8.1 (Berkeley) 05/31/93"; 10 #endif /* not lint */ 11 12 # include "mille.h" 13 14 /* 15 * @(#)comp.c 1.1 (Berkeley) 4/1/82 16 */ 17 18 # define V_VALUABLE 40 19 20 calcmove() 21 { 22 register CARD card; 23 register int *value; 24 register PLAY *pp, *op; 25 register bool foundend, cango, canstop, foundlow; 26 register unsgn int i, count200, badcount, nummin, nummax, diff; 27 register int curmin, curmax; 28 register CARD safe, oppos; 29 int valbuf[HAND_SZ], count[NUM_CARDS]; 30 bool playit[HAND_SZ]; 31 32 wmove(Score, ERR_Y, ERR_X); /* get rid of error messages */ 33 wclrtoeol(Score); 34 pp = &Player[COMP]; 35 op = &Player[PLAYER]; 36 safe = 0; 37 cango = 0; 38 canstop = FALSE; 39 foundend = FALSE; 40 41 /* Try for a Coup Forre, and see what we have. */ 42 for (i = 0; i < NUM_CARDS; i++) 43 count[i] = 0; 44 for (i = 0; i < HAND_SZ; i++) { 45 card = pp->hand[i]; 46 switch (card) { 47 case C_STOP: case C_CRASH: 48 case C_FLAT: case C_EMPTY: 49 if (playit[i] = canplay(pp, op, card)) 50 canstop = TRUE; 51 goto norm; 52 case C_LIMIT: 53 if ((playit[i] = canplay(pp, op, card)) 54 && Numseen[C_25] == Numcards[C_25] 55 && Numseen[C_50] == Numcards[C_50]) 56 canstop = TRUE; 57 goto norm; 58 case C_25: case C_50: case C_75: 59 case C_100: case C_200: 60 if ((playit[i] = canplay(pp, op, card)) 61 && pp->mileage + Value[card] == End) 62 foundend = TRUE; 63 goto norm; 64 default: 65 playit[i] = canplay(pp, op, card); 66 norm: 67 if (playit[i]) 68 ++cango; 69 break; 70 case C_GAS_SAFE: case C_DRIVE_SAFE: 71 case C_SPARE_SAFE: case C_RIGHT_WAY: 72 if (pp->battle == opposite(card) || 73 (pp->speed == C_LIMIT && card == C_RIGHT_WAY)) { 74 Movetype = M_PLAY; 75 Card_no = i; 76 return; 77 } 78 ++safe; 79 playit[i] = TRUE; 80 break; 81 } 82 if (card >= 0) 83 ++count[card]; 84 } 85 86 /* No Coup Forre. Draw to fill hand, then restart, as needed. */ 87 if (pp->hand[0] == C_INIT && Topcard > Deck) { 88 Movetype = M_DRAW; 89 return; 90 } 91 92 #ifdef DEBUG 93 if (Debug) 94 fprintf(outf, "CALCMOVE: cango = %d, canstop = %d, safe = %d\n", 95 cango, canstop, safe); 96 #endif 97 if (foundend) 98 foundend = !check_ext(TRUE); 99 for (i = 0; safe && i < HAND_SZ; i++) { 100 if (issafety(pp->hand[i])) { 101 if (onecard(op) || (foundend && cango && !canstop)) { 102 #ifdef DEBUG 103 if (Debug) 104 fprintf(outf, 105 "CALCMOVE: onecard(op) = %d, foundend = %d\n", 106 onecard(op), foundend); 107 #endif 108 playsafe: 109 Movetype = M_PLAY; 110 Card_no = i; 111 return; 112 } 113 oppos = opposite(pp->hand[i]); 114 if (Numseen[oppos] == Numcards[oppos] && 115 !(pp->hand[i] == C_RIGHT_WAY && 116 Numseen[C_LIMIT] != Numcards[C_LIMIT])) 117 goto playsafe; 118 else if (!cango 119 && (op->can_go || !pp->can_go || Topcard < Deck)) { 120 card = (Topcard - Deck) - roll(1, 10); 121 if ((!pp->mileage) != (!op->mileage)) 122 card -= 7; 123 #ifdef DEBUG 124 if (Debug) 125 fprintf(outf, 126 "CALCMOVE: card = %d, DECK_SZ / 4 = %d\n", 127 card, DECK_SZ / 4); 128 #endif 129 if (card < DECK_SZ / 4) 130 goto playsafe; 131 } 132 safe--; 133 playit[i] = cango; 134 } 135 } 136 if (!pp->can_go && !isrepair(pp->battle)) 137 Numneed[opposite(pp->battle)]++; 138 redoit: 139 foundlow = (cango || count[C_END_LIMIT] != 0 140 || Numseen[C_LIMIT] == Numcards[C_LIMIT] 141 || pp->safety[S_RIGHT_WAY] != S_UNKNOWN); 142 foundend = FALSE; 143 count200 = pp->nummiles[C_200]; 144 badcount = 0; 145 curmax = -1; 146 curmin = 101; 147 nummin = -1; 148 nummax = -1; 149 value = valbuf; 150 for (i = 0; i < HAND_SZ; i++) { 151 card = pp->hand[i]; 152 if (issafety(card) || playit[i] == (cango != 0)) { 153 #ifdef DEBUG 154 if (Debug) 155 fprintf(outf, "CALCMOVE: switch(\"%s\")\n", 156 C_name[card]); 157 #endif 158 switch (card) { 159 case C_25: case C_50: 160 diff = End - pp->mileage; 161 /* avoid getting too close */ 162 if (Topcard > Deck && cango && diff <= 100 163 && diff / Value[card] > count[card] 164 && (card == C_25 || diff % 50 == 0)) { 165 if (card == C_50 && diff - 50 == 25 166 && count[C_25] > 0) 167 goto okay; 168 *value = 0; 169 if (--cango <= 0) 170 goto redoit; 171 break; 172 } 173 okay: 174 *value = (Value[card] >> 3); 175 if (pp->speed == C_LIMIT) 176 ++*value; 177 else 178 --*value; 179 if (!foundlow 180 && (card == C_50 || count[C_50] == 0)) { 181 *value = (pp->mileage ? 10 : 20); 182 foundlow = TRUE; 183 } 184 goto miles; 185 case C_200: 186 if (++count200 > 2) { 187 *value = 0; 188 break; 189 } 190 case C_75: case C_100: 191 *value = (Value[card] >> 3); 192 if (pp->speed == C_LIMIT) 193 --*value; 194 else 195 ++*value; 196 miles: 197 if (pp->mileage + Value[card] > End) 198 *value = (End == 700 ? card : 0); 199 else if (pp->mileage + Value[card] == End) { 200 *value = (foundend ? card : V_VALUABLE); 201 foundend = TRUE; 202 } 203 break; 204 case C_END_LIMIT: 205 if (pp->safety[S_RIGHT_WAY] != S_UNKNOWN) 206 *value = (pp->safety[S_RIGHT_WAY] == 207 S_PLAYED ? -1 : 1); 208 else if (pp->speed == C_LIMIT && 209 End - pp->mileage <= 50) 210 *value = 1; 211 else if (pp->speed == C_LIMIT 212 || Numseen[C_LIMIT] != Numcards[C_LIMIT]) { 213 safe = S_RIGHT_WAY; 214 oppos = C_LIMIT; 215 goto repair; 216 } 217 else { 218 *value = 0; 219 --count[C_END_LIMIT]; 220 } 221 break; 222 case C_REPAIRS: case C_SPARE: case C_GAS: 223 safe = safety(card) - S_CONV; 224 oppos = opposite(card); 225 if (pp->safety[safe] != S_UNKNOWN) 226 *value = (pp->safety[safe] == 227 S_PLAYED ? -1 : 1); 228 else if (pp->battle != oppos 229 && (Numseen[oppos] == Numcards[oppos] || 230 Numseen[oppos] + count[card] > 231 Numcards[oppos])) { 232 *value = 0; 233 --count[card]; 234 } 235 else { 236 repair: 237 *value = Numcards[oppos] * 6; 238 *value += Numseen[card] - 239 Numseen[oppos]; 240 if (!cango) 241 *value /= (count[card]*count[card]); 242 count[card]--; 243 } 244 break; 245 case C_GO: 246 if (pp->safety[S_RIGHT_WAY] != S_UNKNOWN) 247 *value = (pp->safety[S_RIGHT_WAY] == 248 S_PLAYED ? -1 : 2); 249 else if (pp->can_go 250 && Numgos + count[C_GO] == Numneed[C_GO]) { 251 *value = 0; 252 --count[C_GO]; 253 } 254 else { 255 *value = Numneed[C_GO] * 3; 256 *value += (Numseen[C_GO] - Numgos); 257 *value /= (count[C_GO] * count[C_GO]); 258 count[C_GO]--; 259 } 260 break; 261 case C_LIMIT: 262 if (op->mileage + 50 >= End) { 263 *value = (End == 700 && !cango); 264 break; 265 } 266 if (canstop || (cango && !op->can_go)) 267 *value = 1; 268 else { 269 *value = (pp->safety[S_RIGHT_WAY] != 270 S_UNKNOWN ? 2 : 3); 271 safe = S_RIGHT_WAY; 272 oppos = C_END_LIMIT; 273 goto normbad; 274 } 275 break; 276 case C_CRASH: case C_EMPTY: case C_FLAT: 277 safe = safety(card) - S_CONV; 278 oppos = opposite(card); 279 *value = (pp->safety[safe]!=S_UNKNOWN ? 3 : 4); 280 normbad: 281 if (op->safety[safe] == S_PLAYED) 282 *value = -1; 283 else { 284 *value *= Numneed[oppos] + 285 Numseen[oppos] + 2; 286 if (!pp->mileage || foundend || 287 onecard(op)) 288 *value += 5; 289 if (op->mileage == 0 || onecard(op)) 290 *value += 5; 291 if (op->speed == C_LIMIT) 292 *value -= 3; 293 if (cango && 294 pp->safety[safe] != S_UNKNOWN) 295 *value += 3; 296 if (!cango) 297 *value /= ++badcount; 298 } 299 break; 300 case C_STOP: 301 if (op->safety[S_RIGHT_WAY] == S_PLAYED) 302 *value = -1; 303 else { 304 *value = (pp->safety[S_RIGHT_WAY] != 305 S_UNKNOWN ? 3 : 4); 306 *value *= Numcards[C_STOP] + 307 Numseen[C_GO]; 308 if (!pp->mileage || foundend || 309 onecard(op)) 310 *value += 5; 311 if (!cango) 312 *value /= ++badcount; 313 if (op->mileage == 0) 314 *value += 5; 315 if ((card == C_LIMIT && 316 op->speed == C_LIMIT) || 317 !op->can_go) 318 *value -= 5; 319 if (cango && pp->safety[S_RIGHT_WAY] != 320 S_UNKNOWN) 321 *value += 5; 322 } 323 break; 324 case C_GAS_SAFE: case C_DRIVE_SAFE: 325 case C_SPARE_SAFE: case C_RIGHT_WAY: 326 *value = cango ? 0 : 101; 327 break; 328 case C_INIT: 329 *value = 0; 330 break; 331 } 332 } 333 else 334 *value = cango ? 0 : 101; 335 if (card != C_INIT) { 336 if (*value >= curmax) { 337 nummax = i; 338 curmax = *value; 339 } 340 if (*value <= curmin) { 341 nummin = i; 342 curmin = *value; 343 } 344 } 345 #ifdef DEBUG 346 if (Debug) 347 mvprintw(i + 6, 2, "%3d %-14s", *value, 348 C_name[pp->hand[i]]); 349 #endif 350 value++; 351 } 352 if (!pp->can_go && !isrepair(pp->battle)) 353 Numneed[opposite(pp->battle)]++; 354 if (cango) { 355 play_it: 356 mvaddstr(MOVE_Y + 1, MOVE_X, "PLAY\n"); 357 Movetype = M_PLAY; 358 Card_no = nummax; 359 } 360 else { 361 if (issafety(pp->hand[nummin])) { /* NEVER discard a safety */ 362 nummax = nummin; 363 goto play_it; 364 } 365 mvaddstr(MOVE_Y + 1, MOVE_X, "DISCARD\n"); 366 Movetype = M_DISCARD; 367 Card_no = nummin; 368 } 369 mvprintw(MOVE_Y + 2, MOVE_X, "%16s", C_name[pp->hand[Card_no]]); 370 } 371 372 /* 373 * Return true if the given player could conceivably win with his next card. 374 */ 375 onecard(pp) 376 register PLAY *pp; 377 { 378 register CARD bat, spd, card; 379 380 bat = pp->battle; 381 spd = pp->speed; 382 card = -1; 383 if (pp->can_go || ((isrepair(bat) || bat == C_STOP || spd == C_LIMIT) && 384 Numseen[S_RIGHT_WAY] != 0) || 385 bat >= 0 && Numseen[safety(bat)] != 0) 386 switch (End - pp->mileage) { 387 case 200: 388 if (pp->nummiles[C_200] == 2) 389 return FALSE; 390 card = C_200; 391 /* FALLTHROUGH */ 392 case 100: 393 case 75: 394 if (card == -1) 395 card = (End - pp->mileage == 75 ? C_75 : C_100); 396 if (spd == C_LIMIT) 397 return Numseen[S_RIGHT_WAY] == 0; 398 case 50: 399 case 25: 400 if (card == -1) 401 card = (End - pp->mileage == 25 ? C_25 : C_50); 402 return Numseen[card] != Numcards[card]; 403 } 404 return FALSE; 405 } 406 407 canplay(pp, op, card) 408 register PLAY *pp, *op; 409 register CARD card; 410 { 411 switch (card) { 412 case C_200: 413 if (pp->nummiles[C_200] == 2) 414 break; 415 /* FALLTHROUGH */ 416 case C_75: case C_100: 417 if (pp->speed == C_LIMIT) 418 break; 419 /* FALLTHROUGH */ 420 case C_50: 421 if (pp->mileage + Value[card] > End) 422 break; 423 /* FALLTHROUGH */ 424 case C_25: 425 if (pp->can_go) 426 return TRUE; 427 break; 428 case C_EMPTY: case C_FLAT: case C_CRASH: 429 case C_STOP: 430 if (op->can_go && op->safety[safety(card) - S_CONV] != S_PLAYED) 431 return TRUE; 432 break; 433 case C_LIMIT: 434 if (op->speed != C_LIMIT && 435 op->safety[S_RIGHT_WAY] != S_PLAYED && 436 op->mileage + 50 < End) 437 return TRUE; 438 break; 439 case C_GAS: case C_SPARE: case C_REPAIRS: 440 if (pp->battle == opposite(card)) 441 return TRUE; 442 break; 443 case C_GO: 444 if (!pp->can_go && 445 (isrepair(pp->battle) || pp->battle == C_STOP)) 446 return TRUE; 447 break; 448 case C_END_LIMIT: 449 if (pp->speed == C_LIMIT) 450 return TRUE; 451 } 452 return FALSE; 453 } 454