comp.c revision 1.2
1/* 2 * Copyright (c) 1982 Regents of the University of California. 3 * 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 5.4 (Berkeley) 6/1/90";*/ 36static char rcsid[] = "$Id: comp.c,v 1.2 1993/08/01 18:54:05 mycroft 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 for (i = 0; i < NUM_CARDS; i++) 68 count[i] = 0; 69 for (i = 0; i < HAND_SZ; i++) { 70 card = pp->hand[i]; 71 switch (card) { 72 case C_STOP: case C_CRASH: 73 case C_FLAT: case C_EMPTY: 74 if (playit[i] = canplay(pp, op, card)) 75 canstop = TRUE; 76 goto norm; 77 case C_LIMIT: 78 if ((playit[i] = canplay(pp, op, card)) 79 && Numseen[C_25] == Numcards[C_25] 80 && Numseen[C_50] == Numcards[C_50]) 81 canstop = TRUE; 82 goto norm; 83 case C_25: case C_50: case C_75: 84 case C_100: case C_200: 85 if ((playit[i] = canplay(pp, op, card)) 86 && pp->mileage + Value[card] == End) 87 foundend = TRUE; 88 goto norm; 89 default: 90 playit[i] = canplay(pp, op, card); 91norm: 92 if (playit[i]) 93 ++cango; 94 break; 95 case C_GAS_SAFE: case C_DRIVE_SAFE: 96 case C_SPARE_SAFE: case C_RIGHT_WAY: 97 if (pp->battle == opposite(card) || 98 (pp->speed == C_LIMIT && card == C_RIGHT_WAY)) { 99 Movetype = M_PLAY; 100 Card_no = i; 101 return; 102 } 103 ++safe; 104 playit[i] = TRUE; 105 break; 106 } 107 ++count[card]; 108 } 109 if (pp->hand[0] == C_INIT && Topcard > Deck) { 110 Movetype = M_DRAW; 111 return; 112 } 113#ifdef DEBUG 114 if (Debug) 115 fprintf(outf, "CALCMOVE: cango = %d, canstop = %d, safe = %d\n", 116 cango, canstop, safe); 117#endif 118 if (foundend) 119 foundend = !check_ext(TRUE); 120 for (i = 0; safe && i < HAND_SZ; i++) { 121 if (issafety(pp->hand[i])) { 122 if (onecard(op) || (foundend && cango && !canstop)) { 123#ifdef DEBUG 124 if (Debug) 125 fprintf(outf, 126 "CALCMOVE: onecard(op) = %d, foundend = %d\n", 127 onecard(op), foundend); 128#endif 129playsafe: 130 Movetype = M_PLAY; 131 Card_no = i; 132 return; 133 } 134 oppos = opposite(pp->hand[i]); 135 if (Numseen[oppos] == Numcards[oppos] && 136 !(pp->hand[i] == C_RIGHT_WAY && 137 Numseen[C_LIMIT] != Numcards[C_LIMIT])) 138 goto playsafe; 139 else if (!cango 140 && (op->can_go || !pp->can_go || Topcard < Deck)) { 141 card = (Topcard - Deck) - roll(1, 10); 142 if ((!pp->mileage) != (!op->mileage)) 143 card -= 7; 144#ifdef DEBUG 145 if (Debug) 146 fprintf(outf, 147 "CALCMOVE: card = %d, DECK_SZ / 4 = %d\n", 148 card, DECK_SZ / 4); 149#endif 150 if (card < DECK_SZ / 4) 151 goto playsafe; 152 } 153 safe--; 154 playit[i] = cango; 155 } 156 } 157 if (!pp->can_go && !isrepair(pp->battle)) 158 Numneed[opposite(pp->battle)]++; 159redoit: 160 foundlow = (cango || count[C_END_LIMIT] != 0 161 || Numseen[C_LIMIT] == Numcards[C_LIMIT] 162 || pp->safety[S_RIGHT_WAY] != S_UNKNOWN); 163 foundend = FALSE; 164 count200 = pp->nummiles[C_200]; 165 badcount = 0; 166 curmax = -1; 167 curmin = 101; 168 nummin = -1; 169 nummax = -1; 170 value = valbuf; 171 for (i = 0; i < HAND_SZ; i++) { 172 card = pp->hand[i]; 173 if (issafety(card) || playit[i] == (cango != 0)) { 174#ifdef DEBUG 175 if (Debug) 176 fprintf(outf, "CALCMOVE: switch(\"%s\")\n", 177 C_name[card]); 178#endif 179 switch (card) { 180 case C_25: case C_50: 181 diff = End - pp->mileage; 182 /* avoid getting too close */ 183 if (Topcard > Deck && cango && diff <= 100 184 && diff / Value[card] > count[card] 185 && (card == C_25 || diff % 50 == 0)) { 186 if (card == C_50 && diff - 50 == 25 187 && count[C_25] > 0) 188 goto okay; 189 *value = 0; 190 if (--cango <= 0) 191 goto redoit; 192 break; 193 } 194okay: 195 *value = (Value[card] >> 3); 196 if (pp->speed == C_LIMIT) 197 ++*value; 198 else 199 --*value; 200 if (!foundlow 201 && (card == C_50 || count[C_50] == 0)) { 202 *value = (pp->mileage ? 10 : 20); 203 foundlow = TRUE; 204 } 205 goto miles; 206 case C_200: 207 if (++count200 > 2) { 208 *value = 0; 209 break; 210 } 211 case C_75: case C_100: 212 *value = (Value[card] >> 3); 213 if (pp->speed == C_LIMIT) 214 --*value; 215 else 216 ++*value; 217miles: 218 if (pp->mileage + Value[card] > End) 219 *value = (End == 700 ? card : 0); 220 else if (pp->mileage + Value[card] == End) { 221 *value = (foundend ? card : V_VALUABLE); 222 foundend = TRUE; 223 } 224 break; 225 case C_END_LIMIT: 226 if (pp->safety[S_RIGHT_WAY] != S_UNKNOWN) 227 *value = (pp->safety[S_RIGHT_WAY] == 228 S_PLAYED ? -1 : 1); 229 else if (pp->speed == C_LIMIT && 230 End - pp->mileage <= 50) 231 *value = 1; 232 else if (pp->speed == C_LIMIT 233 || Numseen[C_LIMIT] != Numcards[C_LIMIT]) { 234 safe = S_RIGHT_WAY; 235 oppos = C_LIMIT; 236 goto repair; 237 } 238 else { 239 *value = 0; 240 --count[C_END_LIMIT]; 241 } 242 break; 243 case C_REPAIRS: case C_SPARE: case C_GAS: 244 safe = safety(card) - S_CONV; 245 oppos = opposite(card); 246 if (pp->safety[safe] != S_UNKNOWN) 247 *value = (pp->safety[safe] == 248 S_PLAYED ? -1 : 1); 249 else if (pp->battle != oppos 250 && (Numseen[oppos] == Numcards[oppos] || 251 Numseen[oppos] + count[card] > 252 Numcards[oppos])) { 253 *value = 0; 254 --count[card]; 255 } 256 else { 257repair: 258 *value = Numcards[oppos] * 6; 259 *value += Numseen[card] - 260 Numseen[oppos]; 261 if (!cango) 262 *value /= (count[card]*count[card]); 263 count[card]--; 264 } 265 break; 266 case C_GO: 267 if (pp->safety[S_RIGHT_WAY] != S_UNKNOWN) 268 *value = (pp->safety[S_RIGHT_WAY] == 269 S_PLAYED ? -1 : 2); 270 else if (pp->can_go 271 && Numgos + count[C_GO] == Numneed[C_GO]) { 272 *value = 0; 273 --count[C_GO]; 274 } 275 else { 276 *value = Numneed[C_GO] * 3; 277 *value += (Numseen[C_GO] - Numgos); 278 *value /= (count[C_GO] * count[C_GO]); 279 count[C_GO]--; 280 } 281 break; 282 case C_LIMIT: 283 if (op->mileage + 50 >= End) { 284 *value = (End == 700 && !cango); 285 break; 286 } 287 if (canstop || (cango && !op->can_go)) 288 *value = 1; 289 else { 290 *value = (pp->safety[S_RIGHT_WAY] != 291 S_UNKNOWN ? 2 : 3); 292 safe = S_RIGHT_WAY; 293 oppos = C_END_LIMIT; 294 goto normbad; 295 } 296 break; 297 case C_CRASH: case C_EMPTY: case C_FLAT: 298 safe = safety(card) - S_CONV; 299 oppos = opposite(card); 300 *value = (pp->safety[safe]!=S_UNKNOWN ? 3 : 4); 301normbad: 302 if (op->safety[safe] == S_PLAYED) 303 *value = -1; 304 else { 305 *value *= Numneed[oppos] + 306 Numseen[oppos] + 2; 307 if (!pp->mileage || foundend || 308 onecard(op)) 309 *value += 5; 310 if (op->mileage == 0 || onecard(op)) 311 *value += 5; 312 if (op->speed == C_LIMIT) 313 *value -= 3; 314 if (cango && 315 pp->safety[safe] != S_UNKNOWN) 316 *value += 3; 317 if (!cango) 318 *value /= ++badcount; 319 } 320 break; 321 case C_STOP: 322 if (op->safety[S_RIGHT_WAY] == S_PLAYED) 323 *value = -1; 324 else { 325 *value = (pp->safety[S_RIGHT_WAY] != 326 S_UNKNOWN ? 3 : 4); 327 *value *= Numcards[C_STOP] + 328 Numseen[C_GO]; 329 if (!pp->mileage || foundend || 330 onecard(op)) 331 *value += 5; 332 if (!cango) 333 *value /= ++badcount; 334 if (op->mileage == 0) 335 *value += 5; 336 if ((card == C_LIMIT && 337 op->speed == C_LIMIT) || 338 !op->can_go) 339 *value -= 5; 340 if (cango && pp->safety[S_RIGHT_WAY] != 341 S_UNKNOWN) 342 *value += 5; 343 } 344 break; 345 case C_GAS_SAFE: case C_DRIVE_SAFE: 346 case C_SPARE_SAFE: case C_RIGHT_WAY: 347 *value = cango ? 0 : 101; 348 break; 349 case C_INIT: 350 *value = 0; 351 break; 352 } 353 } 354 else 355 *value = cango ? 0 : 101; 356 if (card != C_INIT) { 357 if (*value >= curmax) { 358 nummax = i; 359 curmax = *value; 360 } 361 if (*value <= curmin) { 362 nummin = i; 363 curmin = *value; 364 } 365 } 366#ifdef DEBUG 367 if (Debug) 368 mvprintw(i + 6, 2, "%3d %-14s", *value, 369 C_name[pp->hand[i]]); 370#endif 371 value++; 372 } 373 if (!pp->can_go && !isrepair(pp->battle)) 374 Numneed[opposite(pp->battle)]++; 375 if (cango) { 376play_it: 377 mvaddstr(MOVE_Y + 1, MOVE_X, "PLAY\n"); 378#ifdef DEBUG 379 if (Debug) 380 getmove(); 381 if (!Debug || Movetype == M_DRAW) { 382#else 383 if (Movetype == M_DRAW) { 384#endif 385 Movetype = M_PLAY; 386 Card_no = nummax; 387 } 388 } 389 else { 390 if (issafety(pp->hand[nummin])) { /* NEVER discard a safety */ 391 nummax = nummin; 392 goto play_it; 393 } 394 mvaddstr(MOVE_Y + 1, MOVE_X, "DISCARD\n"); 395#ifdef DEBUG 396 if (Debug) 397 getmove(); 398 if (!Debug || Movetype == M_DRAW) { 399#else 400 if (Movetype == M_DRAW) { 401#endif 402 Movetype = M_DISCARD; 403 Card_no = nummin; 404 } 405 } 406 mvprintw(MOVE_Y + 2, MOVE_X, "%16s", C_name[pp->hand[Card_no]]); 407} 408 409onecard(pp) 410register PLAY *pp; 411{ 412 register CARD bat, spd, card; 413 414 bat = pp->battle; 415 spd = pp->speed; 416 card = -1; 417 if (pp->can_go || ((isrepair(bat) || bat == C_STOP || spd == C_LIMIT) && 418 Numseen[S_RIGHT_WAY] != 0) || 419 Numseen[safety(bat)] != 0) 420 switch (End - pp->mileage) { 421 case 200: 422 if (pp->nummiles[C_200] == 2) 423 return FALSE; 424 card = C_200; 425 /* FALLTHROUGH */ 426 case 100: 427 case 75: 428 if (card == -1) 429 card = (End - pp->mileage == 75 ? C_75 : C_100); 430 if (spd == C_LIMIT) 431 return Numseen[S_RIGHT_WAY] == 0; 432 case 50: 433 case 25: 434 if (card == -1) 435 card = (End - pp->mileage == 25 ? C_25 : C_50); 436 return Numseen[card] != Numcards[card]; 437 } 438 return FALSE; 439} 440 441canplay(pp, op, card) 442register PLAY *pp, *op; 443register CARD card; 444{ 445 switch (card) { 446 case C_200: 447 if (pp->nummiles[C_200] == 2) 448 break; 449 /* FALLTHROUGH */ 450 case C_75: case C_100: 451 if (pp->speed == C_LIMIT) 452 break; 453 /* FALLTHROUGH */ 454 case C_50: 455 if (pp->mileage + Value[card] > End) 456 break; 457 /* FALLTHROUGH */ 458 case C_25: 459 if (pp->can_go) 460 return TRUE; 461 break; 462 case C_EMPTY: case C_FLAT: case C_CRASH: 463 case C_STOP: 464 if (op->can_go && op->safety[safety(card) - S_CONV] != S_PLAYED) 465 return TRUE; 466 break; 467 case C_LIMIT: 468 if (op->speed != C_LIMIT && 469 op->safety[S_RIGHT_WAY] != S_PLAYED && 470 op->mileage + 50 < End) 471 return TRUE; 472 break; 473 case C_GAS: case C_SPARE: case C_REPAIRS: 474 if (pp->battle == opposite(card)) 475 return TRUE; 476 break; 477 case C_GO: 478 if (!pp->can_go && 479 (isrepair(pp->battle) || pp->battle == C_STOP)) 480 return TRUE; 481 break; 482 case C_END_LIMIT: 483 if (pp->speed == C_LIMIT) 484 return TRUE; 485 } 486 return FALSE; 487} 488