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