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