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