xref: /netbsd/games/mille/comp.c (revision bf9ec67e)
1 /*	$NetBSD: comp.c,v 1.8 1999/09/30 18:01:32 jsm Exp $	*/
2 
3 /*
4  * Copyright (c) 1982, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *	This product includes software developed by the University of
18  *	California, Berkeley and its contributors.
19  * 4. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35 
36 #include <sys/cdefs.h>
37 #ifndef lint
38 #if 0
39 static char sccsid[] = "@(#)comp.c	8.1 (Berkeley) 5/31/93";
40 #else
41 __RCSID("$NetBSD: comp.c,v 1.8 1999/09/30 18:01:32 jsm Exp $");
42 #endif
43 #endif /* not lint */
44 
45 # include	"mille.h"
46 
47 /*
48  * @(#)comp.c	1.1 (Berkeley) 4/1/82
49  */
50 
51 # define	V_VALUABLE	40
52 
53 void
54 calcmove()
55 {
56 	CARD		card;
57 	int		*value;
58 	PLAY		*pp, *op;
59 	bool		foundend, cango, canstop, foundlow;
60 	unsgn int	i, count200, badcount, nummin, nummax, diff;
61 	int		curmin, curmax;
62 	CARD		safe, oppos;
63 	int		valbuf[HAND_SZ], count[NUM_CARDS];
64 	bool		playit[HAND_SZ];
65 
66 	wmove(Score, ERR_Y, ERR_X);	/* get rid of error messages	*/
67 	wclrtoeol(Score);
68 	pp = &Player[COMP];
69 	op = &Player[PLAYER];
70 	safe = 0;
71 	cango = 0;
72 	canstop = FALSE;
73 	foundend = FALSE;
74 
75 	/* Try for a Coup Forre, and see what we have. */
76 	for (i = 0; i < NUM_CARDS; i++)
77 		count[i] = 0;
78 	for (i = 0; i < HAND_SZ; i++) {
79 		card = pp->hand[i];
80 		switch (card) {
81 		  case C_STOP:	case C_CRASH:
82 		  case C_FLAT:	case C_EMPTY:
83 			if ((playit[i] = canplay(pp, op, card)) != 0)
84 				canstop = TRUE;
85 			goto norm;
86 		  case C_LIMIT:
87 			if ((playit[i] = canplay(pp, op, card))
88 			    && Numseen[C_25] == Numcards[C_25]
89 			    && Numseen[C_50] == Numcards[C_50])
90 				canstop = TRUE;
91 			goto norm;
92 		  case C_25:	case C_50:	case C_75:
93 		  case C_100:	case C_200:
94 			if ((playit[i] = canplay(pp, op, card))
95 			    && pp->mileage + Value[card] == End)
96 				foundend = TRUE;
97 			goto norm;
98 		  default:
99 			playit[i] = canplay(pp, op, card);
100 norm:
101 			if (playit[i])
102 				++cango;
103 			break;
104 		  case C_GAS_SAFE:	case C_DRIVE_SAFE:
105 		  case C_SPARE_SAFE:	case C_RIGHT_WAY:
106 			if (pp->battle == opposite(card) ||
107 			    (pp->speed == C_LIMIT && card == C_RIGHT_WAY)) {
108 				Movetype = M_PLAY;
109 				Card_no = i;
110 				return;
111 			}
112 			++safe;
113 			playit[i] = TRUE;
114 			break;
115 		}
116 		if (card >= 0)
117 			++count[card];
118 	}
119 
120 	/* No Coup Forre.  Draw to fill hand, then restart, as needed. */
121 	if (pp->hand[0] == C_INIT && Topcard > Deck) {
122 		Movetype = M_DRAW;
123 		return;
124 	}
125 
126 #ifdef DEBUG
127 	if (Debug)
128 		fprintf(outf, "CALCMOVE: cango = %d, canstop = %d, safe = %d\n",
129 			cango, canstop, safe);
130 #endif
131 	if (foundend)
132 		foundend = !check_ext(TRUE);
133 	for (i = 0; safe && i < HAND_SZ; i++) {
134 		if (is_safety(pp->hand[i])) {
135 			if (onecard(op) || (foundend && cango && !canstop)) {
136 #ifdef DEBUG
137 				if (Debug)
138 					fprintf(outf,
139 						"CALCMOVE: onecard(op) = %d, foundend = %d\n",
140 						onecard(op), foundend);
141 #endif
142 playsafe:
143 				Movetype = M_PLAY;
144 				Card_no = i;
145 				return;
146 			}
147 			oppos = opposite(pp->hand[i]);
148 			if (Numseen[oppos] == Numcards[oppos] &&
149 			    !(pp->hand[i] == C_RIGHT_WAY &&
150 			      Numseen[C_LIMIT] != Numcards[C_LIMIT]))
151 				goto playsafe;
152 			else if (!cango
153 			    && (op->can_go || !pp->can_go || Topcard < Deck)) {
154 				card = (Topcard - Deck) - roll(1, 10);
155 				if ((!pp->mileage) != (!op->mileage))
156 					card -= 7;
157 #ifdef DEBUG
158 				if (Debug)
159 					fprintf(outf,
160 						"CALCMOVE: card = %d, DECK_SZ / 4 = %d\n",
161 						card, DECK_SZ / 4);
162 #endif
163 				if (card < DECK_SZ / 4)
164 					goto playsafe;
165 			}
166 			safe--;
167 			playit[i] = cango;
168 		}
169 	}
170 	if (!pp->can_go && !is_repair(pp->battle))
171 		Numneed[opposite(pp->battle)]++;
172 redoit:
173 	foundlow = (cango || count[C_END_LIMIT] != 0
174 			  || Numseen[C_LIMIT] == Numcards[C_LIMIT]
175 			  || pp->safety[S_RIGHT_WAY] != S_UNKNOWN);
176 	foundend = FALSE;
177 	count200 = pp->nummiles[C_200];
178 	badcount = 0;
179 	curmax = -1;
180 	curmin = 101;
181 	nummin = -1;
182 	nummax = -1;
183 	value = valbuf;
184 	for (i = 0; i < HAND_SZ; i++) {
185 		card = pp->hand[i];
186 		if (is_safety(card) || playit[i] == (cango != 0)) {
187 #ifdef DEBUG
188 			if (Debug)
189 				fprintf(outf, "CALCMOVE: switch(\"%s\")\n",
190 					C_name[card]);
191 #endif
192 			switch (card) {
193 			  case C_25:	case C_50:
194 				diff = End - pp->mileage;
195 				/* avoid getting too close */
196 				if (Topcard > Deck && cango && diff <= 100
197 				    && (int)diff / Value[card] > count[card]
198 				    && (card == C_25 || diff % 50 == 0)) {
199 					if (card == C_50 && diff - 50 == 25
200 					    && count[C_25] > 0)
201 						goto okay;
202 					*value = 0;
203 					if (--cango <= 0)
204 						goto redoit;
205 					break;
206 				}
207 okay:
208 				*value = (Value[card] >> 3);
209 				if (pp->speed == C_LIMIT)
210 					++*value;
211 				else
212 					--*value;
213 				if (!foundlow
214 				   && (card == C_50 || count[C_50] == 0)) {
215 					*value = (pp->mileage ? 10 : 20);
216 					foundlow = TRUE;
217 				}
218 				goto miles;
219 			  case C_200:
220 				if (++count200 > 2) {
221 					*value = 0;
222 					break;
223 				}
224 			  case C_75:	case C_100:
225 				*value = (Value[card] >> 3);
226 				if (pp->speed == C_LIMIT)
227 					--*value;
228 				else
229 					++*value;
230 miles:
231 				if (pp->mileage + Value[card] > End)
232 					*value = (End == 700 ? card : 0);
233 				else if (pp->mileage + Value[card] == End) {
234 					*value = (foundend ? card : V_VALUABLE);
235 					foundend = TRUE;
236 				}
237 				break;
238 			  case C_END_LIMIT:
239 				if (pp->safety[S_RIGHT_WAY] != S_UNKNOWN)
240 					*value = (pp->safety[S_RIGHT_WAY] ==
241 						  S_PLAYED ? -1 : 1);
242 				else if (pp->speed == C_LIMIT &&
243 					 End - pp->mileage <= 50)
244 					*value = 1;
245 				else if (pp->speed == C_LIMIT
246 				    || Numseen[C_LIMIT] != Numcards[C_LIMIT]) {
247 					safe = S_RIGHT_WAY;
248 					oppos = C_LIMIT;
249 					goto repair;
250 				}
251 				else {
252 					*value = 0;
253 					--count[C_END_LIMIT];
254 				}
255 				break;
256 			  case C_REPAIRS:	case C_SPARE:	case C_GAS:
257 				safe = safety(card) - S_CONV;
258 				oppos = opposite(card);
259 				if (pp->safety[safe] != S_UNKNOWN)
260 					*value = (pp->safety[safe] ==
261 						  S_PLAYED ? -1 : 1);
262 				else if (pp->battle != oppos
263 				    && (Numseen[oppos] == Numcards[oppos] ||
264 					Numseen[oppos] + count[card] >
265 					Numcards[oppos])) {
266 					*value = 0;
267 					--count[card];
268 				}
269 				else {
270 repair:
271 					*value = Numcards[oppos] * 6;
272 					*value += Numseen[card] -
273 						  Numseen[oppos];
274 					if (!cango)
275 					    *value /= (count[card]*count[card]);
276 					count[card]--;
277 				}
278 				break;
279 			  case C_GO:
280 				if (pp->safety[S_RIGHT_WAY] != S_UNKNOWN)
281 					*value = (pp->safety[S_RIGHT_WAY] ==
282 						  S_PLAYED ? -1 : 2);
283 				else if (pp->can_go
284 				 && Numgos + count[C_GO] == Numneed[C_GO]) {
285 					*value = 0;
286 					--count[C_GO];
287 				}
288 				else {
289 					*value = Numneed[C_GO] * 3;
290 					*value += (Numseen[C_GO] - Numgos);
291 					*value /= (count[C_GO] * count[C_GO]);
292 					count[C_GO]--;
293 				}
294 				break;
295 			  case C_LIMIT:
296 				if (op->mileage + 50 >= End) {
297 					*value = (End == 700 && !cango);
298 					break;
299 				}
300 				if (canstop || (cango && !op->can_go))
301 					*value = 1;
302 				else {
303 					*value = (pp->safety[S_RIGHT_WAY] !=
304 						  S_UNKNOWN ? 2 : 3);
305 					safe = S_RIGHT_WAY;
306 					oppos = C_END_LIMIT;
307 					goto normbad;
308 				}
309 				break;
310 			  case C_CRASH:	case C_EMPTY:	case C_FLAT:
311 				safe = safety(card) - S_CONV;
312 				oppos = opposite(card);
313 				*value = (pp->safety[safe]!=S_UNKNOWN ? 3 : 4);
314 normbad:
315 				if (op->safety[safe] == S_PLAYED)
316 					*value = -1;
317 				else {
318 					*value *= Numneed[oppos] +
319 						  Numseen[oppos] + 2;
320 					if (!pp->mileage || foundend ||
321 					    onecard(op))
322 						*value += 5;
323 					if (op->mileage == 0 || onecard(op))
324 						*value += 5;
325 					if (op->speed == C_LIMIT)
326 						*value -= 3;
327 					if (cango &&
328 					    pp->safety[safe] != S_UNKNOWN)
329 						*value += 3;
330 					if (!cango)
331 						*value /= ++badcount;
332 				}
333 				break;
334 			  case C_STOP:
335 				if (op->safety[S_RIGHT_WAY] == S_PLAYED)
336 					*value = -1;
337 				else {
338 					*value = (pp->safety[S_RIGHT_WAY] !=
339 						  S_UNKNOWN ? 3 : 4);
340 					*value *= Numcards[C_STOP] +
341 						  Numseen[C_GO];
342 					if (!pp->mileage || foundend ||
343 					    onecard(op))
344 						*value += 5;
345 					if (!cango)
346 						*value /= ++badcount;
347 					if (op->mileage == 0)
348 						*value += 5;
349 					if ((card == C_LIMIT &&
350 					     op->speed == C_LIMIT) ||
351 					    !op->can_go)
352 						*value -= 5;
353 					if (cango && pp->safety[S_RIGHT_WAY] !=
354 						     S_UNKNOWN)
355 						*value += 5;
356 				}
357 				break;
358 			  case C_GAS_SAFE:	case C_DRIVE_SAFE:
359 			  case C_SPARE_SAFE:	case C_RIGHT_WAY:
360 				*value = cango ? 0 : 101;
361 				break;
362 			  case C_INIT:
363 				*value = 0;
364 				break;
365 			}
366 		}
367 		else
368 			*value = cango ? 0 : 101;
369 		if (card != C_INIT) {
370 			if (*value >= curmax) {
371 				nummax = i;
372 				curmax = *value;
373 			}
374 			if (*value <= curmin) {
375 				nummin = i;
376 				curmin = *value;
377 			}
378 		}
379 #ifdef DEBUG
380 		if (Debug)
381 			mvprintw(i + 6, 2, "%3d %-14s", *value,
382 				 C_name[pp->hand[i]]);
383 #endif
384 		value++;
385 	}
386 	if (!pp->can_go && !is_repair(pp->battle))
387 		Numneed[opposite(pp->battle)]++;
388 	if (cango) {
389 play_it:
390 		mvaddstr(MOVE_Y + 1, MOVE_X, "PLAY\n");
391 		Movetype = M_PLAY;
392 		Card_no = nummax;
393 	}
394 	else {
395 		if (is_safety(pp->hand[nummin])) { /* NEVER discard a safety */
396 			nummax = nummin;
397 			goto play_it;
398 		}
399 		mvaddstr(MOVE_Y + 1, MOVE_X, "DISCARD\n");
400 		Movetype = M_DISCARD;
401 		Card_no = nummin;
402 	}
403 	mvprintw(MOVE_Y + 2, MOVE_X, "%16s", C_name[pp->hand[Card_no]]);
404 }
405 
406 /*
407  * Return true if the given player could conceivably win with his next card.
408  */
409 int
410 onecard(pp)
411 	const PLAY	*pp;
412 {
413 	CARD	bat, spd, card;
414 
415 	bat = pp->battle;
416 	spd = pp->speed;
417 	card = -1;
418 	if (pp->can_go || ((is_repair(bat) || bat == C_STOP || spd == C_LIMIT) &&
419 			   Numseen[S_RIGHT_WAY] != 0) ||
420 	    (bat >= 0 && Numseen[safety(bat)] != 0))
421 		switch (End - pp->mileage) {
422 		  case 200:
423 			if (pp->nummiles[C_200] == 2)
424 				return FALSE;
425 			card = C_200;
426 			/* FALLTHROUGH */
427 		  case 100:
428 		  case 75:
429 			if (card == -1)
430 				card = (End - pp->mileage == 75 ? C_75 : C_100);
431 			if (spd == C_LIMIT)
432 				return Numseen[S_RIGHT_WAY] == 0;
433 		  case 50:
434 		  case 25:
435 			if (card == -1)
436 				card = (End - pp->mileage == 25 ? C_25 : C_50);
437 			return Numseen[card] != Numcards[card];
438 		}
439 	return FALSE;
440 }
441 
442 int
443 canplay(pp, op, card)
444 	const PLAY	*pp, *op;
445 	CARD	card;
446 {
447 	switch (card) {
448 	  case C_200:
449 		if (pp->nummiles[C_200] == 2)
450 			break;
451 		/* FALLTHROUGH */
452 	  case C_75:	case C_100:
453 		if (pp->speed == C_LIMIT)
454 			break;
455 		/* FALLTHROUGH */
456 	  case C_50:
457 		if (pp->mileage + Value[card] > End)
458 			break;
459 		/* FALLTHROUGH */
460 	  case C_25:
461 		if (pp->can_go)
462 			return TRUE;
463 		break;
464 	  case C_EMPTY:	case C_FLAT:	case C_CRASH:
465 	  case C_STOP:
466 		if (op->can_go && op->safety[safety(card) - S_CONV] != S_PLAYED)
467 			return TRUE;
468 		break;
469 	  case C_LIMIT:
470 		if (op->speed != C_LIMIT &&
471 		    op->safety[S_RIGHT_WAY] != S_PLAYED &&
472 		    op->mileage + 50 < End)
473 			return TRUE;
474 		break;
475 	  case C_GAS:	case C_SPARE:	case C_REPAIRS:
476 		if (pp->battle == opposite(card))
477 			return TRUE;
478 		break;
479 	  case C_GO:
480 		if (!pp->can_go &&
481 		    (is_repair(pp->battle) || pp->battle == C_STOP))
482 			return TRUE;
483 		break;
484 	  case C_END_LIMIT:
485 		if (pp->speed == C_LIMIT)
486 			return TRUE;
487 	}
488 	return FALSE;
489 }
490