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