xref: /csrg-svn/games/mille/comp.c (revision 60812)
130198Sbostic /*
2*60812Sbostic  * Copyright (c) 1982, 1993
3*60812Sbostic  *	The Regents of the University of California.  All rights reserved.
433170Sbostic  *
542578Sbostic  * %sccs.include.redist.c%
630198Sbostic  */
730198Sbostic 
830198Sbostic #ifndef lint
9*60812Sbostic static char sccsid[] = "@(#)comp.c	8.1 (Berkeley) 05/31/93";
1033170Sbostic #endif /* not lint */
1130198Sbostic 
1230198Sbostic # include	"mille.h"
1330198Sbostic 
1430198Sbostic /*
1530198Sbostic  * @(#)comp.c	1.1 (Berkeley) 4/1/82
1630198Sbostic  */
1730198Sbostic 
1830198Sbostic # define	V_VALUABLE	40
1930198Sbostic 
calcmove()2030198Sbostic calcmove()
2130198Sbostic {
2230198Sbostic 	register CARD		card;
2330198Sbostic 	register int		*value;
2430198Sbostic 	register PLAY		*pp, *op;
2530198Sbostic 	register bool		foundend, cango, canstop, foundlow;
2630198Sbostic 	register unsgn int	i, count200, badcount, nummin, nummax, diff;
2730198Sbostic 	register int		curmin, curmax;
2830198Sbostic 	register CARD		safe, oppos;
2930198Sbostic 	int			valbuf[HAND_SZ], count[NUM_CARDS];
3030198Sbostic 	bool			playit[HAND_SZ];
3130198Sbostic 
3230198Sbostic 	wmove(Score, ERR_Y, ERR_X);	/* get rid of error messages	*/
3330198Sbostic 	wclrtoeol(Score);
3430198Sbostic 	pp = &Player[COMP];
3530198Sbostic 	op = &Player[PLAYER];
3630198Sbostic 	safe = 0;
3730198Sbostic 	cango = 0;
3830198Sbostic 	canstop = FALSE;
3930198Sbostic 	foundend = FALSE;
4052876Storek 
4152876Storek 	/* Try for a Coup Forre, and see what we have. */
4230198Sbostic 	for (i = 0; i < NUM_CARDS; i++)
4330198Sbostic 		count[i] = 0;
4430198Sbostic 	for (i = 0; i < HAND_SZ; i++) {
4530198Sbostic 		card = pp->hand[i];
4630198Sbostic 		switch (card) {
4730198Sbostic 		  case C_STOP:	case C_CRASH:
4830198Sbostic 		  case C_FLAT:	case C_EMPTY:
4930198Sbostic 			if (playit[i] = canplay(pp, op, card))
5030198Sbostic 				canstop = TRUE;
5130198Sbostic 			goto norm;
5230198Sbostic 		  case C_LIMIT:
5330198Sbostic 			if ((playit[i] = canplay(pp, op, card))
5430198Sbostic 			    && Numseen[C_25] == Numcards[C_25]
5530198Sbostic 			    && Numseen[C_50] == Numcards[C_50])
5630198Sbostic 				canstop = TRUE;
5730198Sbostic 			goto norm;
5830198Sbostic 		  case C_25:	case C_50:	case C_75:
5930198Sbostic 		  case C_100:	case C_200:
6030198Sbostic 			if ((playit[i] = canplay(pp, op, card))
6130198Sbostic 			    && pp->mileage + Value[card] == End)
6230198Sbostic 				foundend = TRUE;
6330198Sbostic 			goto norm;
6430198Sbostic 		  default:
6530198Sbostic 			playit[i] = canplay(pp, op, card);
6630198Sbostic norm:
6730198Sbostic 			if (playit[i])
6830198Sbostic 				++cango;
6930198Sbostic 			break;
7030198Sbostic 		  case C_GAS_SAFE:	case C_DRIVE_SAFE:
7130198Sbostic 		  case C_SPARE_SAFE:	case C_RIGHT_WAY:
7230198Sbostic 			if (pp->battle == opposite(card) ||
7330198Sbostic 			    (pp->speed == C_LIMIT && card == C_RIGHT_WAY)) {
7430198Sbostic 				Movetype = M_PLAY;
7530198Sbostic 				Card_no = i;
7630198Sbostic 				return;
7730198Sbostic 			}
7830198Sbostic 			++safe;
7930198Sbostic 			playit[i] = TRUE;
8030198Sbostic 			break;
8130198Sbostic 		}
8252876Storek 		if (card >= 0)
8352876Storek 			++count[card];
8430198Sbostic 	}
8552876Storek 
8652876Storek 	/* No Coup Forre.  Draw to fill hand, then restart, as needed. */
8730198Sbostic 	if (pp->hand[0] == C_INIT && Topcard > Deck) {
8830198Sbostic 		Movetype = M_DRAW;
8930198Sbostic 		return;
9030198Sbostic 	}
9152876Storek 
9233170Sbostic #ifdef DEBUG
9330198Sbostic 	if (Debug)
9430198Sbostic 		fprintf(outf, "CALCMOVE: cango = %d, canstop = %d, safe = %d\n",
9530198Sbostic 			cango, canstop, safe);
9633170Sbostic #endif
9730198Sbostic 	if (foundend)
9830198Sbostic 		foundend = !check_ext(TRUE);
9930198Sbostic 	for (i = 0; safe && i < HAND_SZ; i++) {
10030198Sbostic 		if (issafety(pp->hand[i])) {
10130198Sbostic 			if (onecard(op) || (foundend && cango && !canstop)) {
10233170Sbostic #ifdef DEBUG
10330198Sbostic 				if (Debug)
10430198Sbostic 					fprintf(outf,
10530198Sbostic 						"CALCMOVE: onecard(op) = %d, foundend = %d\n",
10630198Sbostic 						onecard(op), foundend);
10733170Sbostic #endif
10830198Sbostic playsafe:
10930198Sbostic 				Movetype = M_PLAY;
11030198Sbostic 				Card_no = i;
11130198Sbostic 				return;
11230198Sbostic 			}
11330198Sbostic 			oppos = opposite(pp->hand[i]);
11430198Sbostic 			if (Numseen[oppos] == Numcards[oppos] &&
11530198Sbostic 			    !(pp->hand[i] == C_RIGHT_WAY &&
11630198Sbostic 			      Numseen[C_LIMIT] != Numcards[C_LIMIT]))
11730198Sbostic 				goto playsafe;
11830198Sbostic 			else if (!cango
11930198Sbostic 			    && (op->can_go || !pp->can_go || Topcard < Deck)) {
12030198Sbostic 				card = (Topcard - Deck) - roll(1, 10);
12130198Sbostic 				if ((!pp->mileage) != (!op->mileage))
12230198Sbostic 					card -= 7;
12333170Sbostic #ifdef DEBUG
12430198Sbostic 				if (Debug)
12530198Sbostic 					fprintf(outf,
12630198Sbostic 						"CALCMOVE: card = %d, DECK_SZ / 4 = %d\n",
12730198Sbostic 						card, DECK_SZ / 4);
12833170Sbostic #endif
12930198Sbostic 				if (card < DECK_SZ / 4)
13030198Sbostic 					goto playsafe;
13130198Sbostic 			}
13230198Sbostic 			safe--;
13330198Sbostic 			playit[i] = cango;
13430198Sbostic 		}
13530198Sbostic 	}
13630198Sbostic 	if (!pp->can_go && !isrepair(pp->battle))
13730198Sbostic 		Numneed[opposite(pp->battle)]++;
13830198Sbostic redoit:
13930198Sbostic 	foundlow = (cango || count[C_END_LIMIT] != 0
14030198Sbostic 			  || Numseen[C_LIMIT] == Numcards[C_LIMIT]
14130198Sbostic 			  || pp->safety[S_RIGHT_WAY] != S_UNKNOWN);
14230198Sbostic 	foundend = FALSE;
14330198Sbostic 	count200 = pp->nummiles[C_200];
14430198Sbostic 	badcount = 0;
14530198Sbostic 	curmax = -1;
14630198Sbostic 	curmin = 101;
14730198Sbostic 	nummin = -1;
14830198Sbostic 	nummax = -1;
14930198Sbostic 	value = valbuf;
15030198Sbostic 	for (i = 0; i < HAND_SZ; i++) {
15130198Sbostic 		card = pp->hand[i];
15230198Sbostic 		if (issafety(card) || playit[i] == (cango != 0)) {
15333170Sbostic #ifdef DEBUG
15430198Sbostic 			if (Debug)
15530198Sbostic 				fprintf(outf, "CALCMOVE: switch(\"%s\")\n",
15630198Sbostic 					C_name[card]);
15733170Sbostic #endif
15830198Sbostic 			switch (card) {
15930198Sbostic 			  case C_25:	case C_50:
16030198Sbostic 				diff = End - pp->mileage;
16130198Sbostic 				/* avoid getting too close */
16230198Sbostic 				if (Topcard > Deck && cango && diff <= 100
16330198Sbostic 				    && diff / Value[card] > count[card]
16430198Sbostic 				    && (card == C_25 || diff % 50 == 0)) {
16530198Sbostic 					if (card == C_50 && diff - 50 == 25
16630198Sbostic 					    && count[C_25] > 0)
16730198Sbostic 						goto okay;
16830198Sbostic 					*value = 0;
16930198Sbostic 					if (--cango <= 0)
17030198Sbostic 						goto redoit;
17130198Sbostic 					break;
17230198Sbostic 				}
17330198Sbostic okay:
17430198Sbostic 				*value = (Value[card] >> 3);
17530198Sbostic 				if (pp->speed == C_LIMIT)
17630198Sbostic 					++*value;
17730198Sbostic 				else
17830198Sbostic 					--*value;
17930198Sbostic 				if (!foundlow
18030198Sbostic 				   && (card == C_50 || count[C_50] == 0)) {
18130198Sbostic 					*value = (pp->mileage ? 10 : 20);
18230198Sbostic 					foundlow = TRUE;
18330198Sbostic 				}
18430198Sbostic 				goto miles;
18530198Sbostic 			  case C_200:
18630198Sbostic 				if (++count200 > 2) {
18730198Sbostic 					*value = 0;
18830198Sbostic 					break;
18930198Sbostic 				}
19030198Sbostic 			  case C_75:	case C_100:
19130198Sbostic 				*value = (Value[card] >> 3);
19230198Sbostic 				if (pp->speed == C_LIMIT)
19330198Sbostic 					--*value;
19430198Sbostic 				else
19530198Sbostic 					++*value;
19630198Sbostic miles:
19730198Sbostic 				if (pp->mileage + Value[card] > End)
19830198Sbostic 					*value = (End == 700 ? card : 0);
19930198Sbostic 				else if (pp->mileage + Value[card] == End) {
20030198Sbostic 					*value = (foundend ? card : V_VALUABLE);
20130198Sbostic 					foundend = TRUE;
20230198Sbostic 				}
20330198Sbostic 				break;
20430198Sbostic 			  case C_END_LIMIT:
20530198Sbostic 				if (pp->safety[S_RIGHT_WAY] != S_UNKNOWN)
20630198Sbostic 					*value = (pp->safety[S_RIGHT_WAY] ==
20730198Sbostic 						  S_PLAYED ? -1 : 1);
20830198Sbostic 				else if (pp->speed == C_LIMIT &&
20930198Sbostic 					 End - pp->mileage <= 50)
21030198Sbostic 					*value = 1;
21130198Sbostic 				else if (pp->speed == C_LIMIT
21230198Sbostic 				    || Numseen[C_LIMIT] != Numcards[C_LIMIT]) {
21330198Sbostic 					safe = S_RIGHT_WAY;
21430198Sbostic 					oppos = C_LIMIT;
21530198Sbostic 					goto repair;
21630198Sbostic 				}
21730198Sbostic 				else {
21830198Sbostic 					*value = 0;
21930198Sbostic 					--count[C_END_LIMIT];
22030198Sbostic 				}
22130198Sbostic 				break;
22230198Sbostic 			  case C_REPAIRS:	case C_SPARE:	case C_GAS:
22330198Sbostic 				safe = safety(card) - S_CONV;
22430198Sbostic 				oppos = opposite(card);
22530198Sbostic 				if (pp->safety[safe] != S_UNKNOWN)
22630198Sbostic 					*value = (pp->safety[safe] ==
22730198Sbostic 						  S_PLAYED ? -1 : 1);
22830198Sbostic 				else if (pp->battle != oppos
22930198Sbostic 				    && (Numseen[oppos] == Numcards[oppos] ||
23030198Sbostic 					Numseen[oppos] + count[card] >
23130198Sbostic 					Numcards[oppos])) {
23230198Sbostic 					*value = 0;
23330198Sbostic 					--count[card];
23430198Sbostic 				}
23530198Sbostic 				else {
23630198Sbostic repair:
23730198Sbostic 					*value = Numcards[oppos] * 6;
23830198Sbostic 					*value += Numseen[card] -
23930198Sbostic 						  Numseen[oppos];
24030198Sbostic 					if (!cango)
24130198Sbostic 					    *value /= (count[card]*count[card]);
24230198Sbostic 					count[card]--;
24330198Sbostic 				}
24430198Sbostic 				break;
24530198Sbostic 			  case C_GO:
24630198Sbostic 				if (pp->safety[S_RIGHT_WAY] != S_UNKNOWN)
24730198Sbostic 					*value = (pp->safety[S_RIGHT_WAY] ==
24830198Sbostic 						  S_PLAYED ? -1 : 2);
24930198Sbostic 				else if (pp->can_go
25030198Sbostic 				 && Numgos + count[C_GO] == Numneed[C_GO]) {
25130198Sbostic 					*value = 0;
25230198Sbostic 					--count[C_GO];
25330198Sbostic 				}
25430198Sbostic 				else {
25530198Sbostic 					*value = Numneed[C_GO] * 3;
25630198Sbostic 					*value += (Numseen[C_GO] - Numgos);
25730198Sbostic 					*value /= (count[C_GO] * count[C_GO]);
25830198Sbostic 					count[C_GO]--;
25930198Sbostic 				}
26030198Sbostic 				break;
26130198Sbostic 			  case C_LIMIT:
26230198Sbostic 				if (op->mileage + 50 >= End) {
26330198Sbostic 					*value = (End == 700 && !cango);
26430198Sbostic 					break;
26530198Sbostic 				}
26630198Sbostic 				if (canstop || (cango && !op->can_go))
26730198Sbostic 					*value = 1;
26830198Sbostic 				else {
26930198Sbostic 					*value = (pp->safety[S_RIGHT_WAY] !=
27030198Sbostic 						  S_UNKNOWN ? 2 : 3);
27130198Sbostic 					safe = S_RIGHT_WAY;
27230198Sbostic 					oppos = C_END_LIMIT;
27330198Sbostic 					goto normbad;
27430198Sbostic 				}
27530198Sbostic 				break;
27630198Sbostic 			  case C_CRASH:	case C_EMPTY:	case C_FLAT:
27730198Sbostic 				safe = safety(card) - S_CONV;
27830198Sbostic 				oppos = opposite(card);
27930198Sbostic 				*value = (pp->safety[safe]!=S_UNKNOWN ? 3 : 4);
28030198Sbostic normbad:
28130198Sbostic 				if (op->safety[safe] == S_PLAYED)
28230198Sbostic 					*value = -1;
28330198Sbostic 				else {
28430198Sbostic 					*value *= Numneed[oppos] +
28530198Sbostic 						  Numseen[oppos] + 2;
28630198Sbostic 					if (!pp->mileage || foundend ||
28730198Sbostic 					    onecard(op))
28830198Sbostic 						*value += 5;
28930198Sbostic 					if (op->mileage == 0 || onecard(op))
29030198Sbostic 						*value += 5;
29130198Sbostic 					if (op->speed == C_LIMIT)
29230198Sbostic 						*value -= 3;
29330198Sbostic 					if (cango &&
29430198Sbostic 					    pp->safety[safe] != S_UNKNOWN)
29530198Sbostic 						*value += 3;
29630198Sbostic 					if (!cango)
29730198Sbostic 						*value /= ++badcount;
29830198Sbostic 				}
29930198Sbostic 				break;
30030198Sbostic 			  case C_STOP:
30130198Sbostic 				if (op->safety[S_RIGHT_WAY] == S_PLAYED)
30230198Sbostic 					*value = -1;
30330198Sbostic 				else {
30430198Sbostic 					*value = (pp->safety[S_RIGHT_WAY] !=
30530198Sbostic 						  S_UNKNOWN ? 3 : 4);
30630198Sbostic 					*value *= Numcards[C_STOP] +
30730198Sbostic 						  Numseen[C_GO];
30830198Sbostic 					if (!pp->mileage || foundend ||
30930198Sbostic 					    onecard(op))
31030198Sbostic 						*value += 5;
31130198Sbostic 					if (!cango)
31230198Sbostic 						*value /= ++badcount;
31330198Sbostic 					if (op->mileage == 0)
31430198Sbostic 						*value += 5;
31530198Sbostic 					if ((card == C_LIMIT &&
31630198Sbostic 					     op->speed == C_LIMIT) ||
31730198Sbostic 					    !op->can_go)
31830198Sbostic 						*value -= 5;
31930198Sbostic 					if (cango && pp->safety[S_RIGHT_WAY] !=
32030198Sbostic 						     S_UNKNOWN)
32130198Sbostic 						*value += 5;
32230198Sbostic 				}
32330198Sbostic 				break;
32430198Sbostic 			  case C_GAS_SAFE:	case C_DRIVE_SAFE:
32530198Sbostic 			  case C_SPARE_SAFE:	case C_RIGHT_WAY:
32630198Sbostic 				*value = cango ? 0 : 101;
32730198Sbostic 				break;
32830198Sbostic 			  case C_INIT:
32930198Sbostic 				*value = 0;
33030198Sbostic 				break;
33130198Sbostic 			}
33230198Sbostic 		}
33330198Sbostic 		else
33430198Sbostic 			*value = cango ? 0 : 101;
33530198Sbostic 		if (card != C_INIT) {
33630198Sbostic 			if (*value >= curmax) {
33730198Sbostic 				nummax = i;
33830198Sbostic 				curmax = *value;
33930198Sbostic 			}
34030198Sbostic 			if (*value <= curmin) {
34130198Sbostic 				nummin = i;
34230198Sbostic 				curmin = *value;
34330198Sbostic 			}
34430198Sbostic 		}
34533170Sbostic #ifdef DEBUG
34630198Sbostic 		if (Debug)
34730198Sbostic 			mvprintw(i + 6, 2, "%3d %-14s", *value,
34830198Sbostic 				 C_name[pp->hand[i]]);
34933170Sbostic #endif
35030198Sbostic 		value++;
35130198Sbostic 	}
35230198Sbostic 	if (!pp->can_go && !isrepair(pp->battle))
35330198Sbostic 		Numneed[opposite(pp->battle)]++;
35430198Sbostic 	if (cango) {
35530198Sbostic play_it:
35630198Sbostic 		mvaddstr(MOVE_Y + 1, MOVE_X, "PLAY\n");
35752876Storek 		Movetype = M_PLAY;
35852876Storek 		Card_no = nummax;
35930198Sbostic 	}
36030198Sbostic 	else {
36130198Sbostic 		if (issafety(pp->hand[nummin])) { /* NEVER discard a safety */
36230198Sbostic 			nummax = nummin;
36330198Sbostic 			goto play_it;
36430198Sbostic 		}
36530198Sbostic 		mvaddstr(MOVE_Y + 1, MOVE_X, "DISCARD\n");
36652876Storek 		Movetype = M_DISCARD;
36752876Storek 		Card_no = nummin;
36830198Sbostic 	}
36930198Sbostic 	mvprintw(MOVE_Y + 2, MOVE_X, "%16s", C_name[pp->hand[Card_no]]);
37030198Sbostic }
37130198Sbostic 
37252876Storek /*
37352876Storek  * Return true if the given player could conceivably win with his next card.
37452876Storek  */
onecard(pp)37530198Sbostic onecard(pp)
37630198Sbostic register PLAY	*pp;
37730198Sbostic {
37830198Sbostic 	register CARD	bat, spd, card;
37930198Sbostic 
38030198Sbostic 	bat = pp->battle;
38130198Sbostic 	spd = pp->speed;
38230198Sbostic 	card = -1;
38330198Sbostic 	if (pp->can_go || ((isrepair(bat) || bat == C_STOP || spd == C_LIMIT) &&
38430198Sbostic 			   Numseen[S_RIGHT_WAY] != 0) ||
38552872Storek 	    bat >= 0 && Numseen[safety(bat)] != 0)
38630198Sbostic 		switch (End - pp->mileage) {
38730198Sbostic 		  case 200:
38830198Sbostic 			if (pp->nummiles[C_200] == 2)
38930198Sbostic 				return FALSE;
39030198Sbostic 			card = C_200;
39130198Sbostic 			/* FALLTHROUGH */
39230198Sbostic 		  case 100:
39330198Sbostic 		  case 75:
39430198Sbostic 			if (card == -1)
39530198Sbostic 				card = (End - pp->mileage == 75 ? C_75 : C_100);
39630198Sbostic 			if (spd == C_LIMIT)
39730198Sbostic 				return Numseen[S_RIGHT_WAY] == 0;
39830198Sbostic 		  case 50:
39930198Sbostic 		  case 25:
40030198Sbostic 			if (card == -1)
40130198Sbostic 				card = (End - pp->mileage == 25 ? C_25 : C_50);
40230198Sbostic 			return Numseen[card] != Numcards[card];
40330198Sbostic 		}
40430198Sbostic 	return FALSE;
40530198Sbostic }
40630198Sbostic 
canplay(pp,op,card)40730198Sbostic canplay(pp, op, card)
40830198Sbostic register PLAY	*pp, *op;
40930198Sbostic register CARD	card;
41030198Sbostic {
41130198Sbostic 	switch (card) {
41230198Sbostic 	  case C_200:
41330198Sbostic 		if (pp->nummiles[C_200] == 2)
41430198Sbostic 			break;
41530198Sbostic 		/* FALLTHROUGH */
41630198Sbostic 	  case C_75:	case C_100:
41730198Sbostic 		if (pp->speed == C_LIMIT)
41830198Sbostic 			break;
41930198Sbostic 		/* FALLTHROUGH */
42030198Sbostic 	  case C_50:
42130198Sbostic 		if (pp->mileage + Value[card] > End)
42230198Sbostic 			break;
42330198Sbostic 		/* FALLTHROUGH */
42430198Sbostic 	  case C_25:
42530198Sbostic 		if (pp->can_go)
42630198Sbostic 			return TRUE;
42730198Sbostic 		break;
42830198Sbostic 	  case C_EMPTY:	case C_FLAT:	case C_CRASH:
42930198Sbostic 	  case C_STOP:
43030198Sbostic 		if (op->can_go && op->safety[safety(card) - S_CONV] != S_PLAYED)
43130198Sbostic 			return TRUE;
43230198Sbostic 		break;
43330198Sbostic 	  case C_LIMIT:
43430198Sbostic 		if (op->speed != C_LIMIT &&
43530198Sbostic 		    op->safety[S_RIGHT_WAY] != S_PLAYED &&
43630198Sbostic 		    op->mileage + 50 < End)
43730198Sbostic 			return TRUE;
43830198Sbostic 		break;
43930198Sbostic 	  case C_GAS:	case C_SPARE:	case C_REPAIRS:
44030198Sbostic 		if (pp->battle == opposite(card))
44130198Sbostic 			return TRUE;
44230198Sbostic 		break;
44330198Sbostic 	  case C_GO:
44430198Sbostic 		if (!pp->can_go &&
44530198Sbostic 		    (isrepair(pp->battle) || pp->battle == C_STOP))
44630198Sbostic 			return TRUE;
44730198Sbostic 		break;
44830198Sbostic 	  case C_END_LIMIT:
44930198Sbostic 		if (pp->speed == C_LIMIT)
45030198Sbostic 			return TRUE;
45130198Sbostic 	}
45230198Sbostic 	return FALSE;
45330198Sbostic }
454