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