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