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