comp.c revision 1.2
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";*/
36static 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
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	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);
91norm:
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
129playsafe:
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)]++;
159redoit:
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				}
194okay:
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;
217miles:
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 {
257repair:
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);
301normbad:
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) {
376play_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
409onecard(pp)
410register 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
441canplay(pp, op, card)
442register PLAY	*pp, *op;
443register 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