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