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