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