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