]> git.cameronkatri.com Git - bsdgames-darwin.git/blob - mille/comp.c
* Change program logic to not nest needlessly
[bsdgames-darwin.git] / mille / comp.c
1 /* $NetBSD: comp.c,v 1.9 2003/08/07 09:37:24 agc 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. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 #ifndef lint
34 #if 0
35 static char sccsid[] = "@(#)comp.c 8.1 (Berkeley) 5/31/93";
36 #else
37 __RCSID("$NetBSD: comp.c,v 1.9 2003/08/07 09:37:24 agc Exp $");
38 #endif
39 #endif /* not lint */
40
41 # include "mille.h"
42
43 /*
44 * @(#)comp.c 1.1 (Berkeley) 4/1/82
45 */
46
47 # define V_VALUABLE 40
48
49 void
50 calcmove()
51 {
52 CARD card;
53 int *value;
54 PLAY *pp, *op;
55 bool foundend, cango, canstop, foundlow;
56 unsgn int i, count200, badcount, nummin, nummax, diff;
57 int curmin, curmax;
58 CARD safe, oppos;
59 int valbuf[HAND_SZ], count[NUM_CARDS];
60 bool playit[HAND_SZ];
61
62 wmove(Score, ERR_Y, ERR_X); /* get rid of error messages */
63 wclrtoeol(Score);
64 pp = &Player[COMP];
65 op = &Player[PLAYER];
66 safe = 0;
67 cango = 0;
68 canstop = FALSE;
69 foundend = FALSE;
70
71 /* Try for a Coup Forre, and see what we have. */
72 for (i = 0; i < NUM_CARDS; i++)
73 count[i] = 0;
74 for (i = 0; i < HAND_SZ; i++) {
75 card = pp->hand[i];
76 switch (card) {
77 case C_STOP: case C_CRASH:
78 case C_FLAT: case C_EMPTY:
79 if ((playit[i] = canplay(pp, op, card)) != 0)
80 canstop = TRUE;
81 goto norm;
82 case C_LIMIT:
83 if ((playit[i] = canplay(pp, op, card))
84 && Numseen[C_25] == Numcards[C_25]
85 && Numseen[C_50] == Numcards[C_50])
86 canstop = TRUE;
87 goto norm;
88 case C_25: case C_50: case C_75:
89 case C_100: case C_200:
90 if ((playit[i] = canplay(pp, op, card))
91 && pp->mileage + Value[card] == End)
92 foundend = TRUE;
93 goto norm;
94 default:
95 playit[i] = canplay(pp, op, card);
96 norm:
97 if (playit[i])
98 ++cango;
99 break;
100 case C_GAS_SAFE: case C_DRIVE_SAFE:
101 case C_SPARE_SAFE: case C_RIGHT_WAY:
102 if (pp->battle == opposite(card) ||
103 (pp->speed == C_LIMIT && card == C_RIGHT_WAY)) {
104 Movetype = M_PLAY;
105 Card_no = i;
106 return;
107 }
108 ++safe;
109 playit[i] = TRUE;
110 break;
111 }
112 if (card >= 0)
113 ++count[card];
114 }
115
116 /* No Coup Forre. Draw to fill hand, then restart, as needed. */
117 if (pp->hand[0] == C_INIT && Topcard > Deck) {
118 Movetype = M_DRAW;
119 return;
120 }
121
122 #ifdef DEBUG
123 if (Debug)
124 fprintf(outf, "CALCMOVE: cango = %d, canstop = %d, safe = %d\n",
125 cango, canstop, safe);
126 #endif
127 if (foundend)
128 foundend = !check_ext(TRUE);
129 for (i = 0; safe && i < HAND_SZ; i++) {
130 if (is_safety(pp->hand[i])) {
131 if (onecard(op) || (foundend && cango && !canstop)) {
132 #ifdef DEBUG
133 if (Debug)
134 fprintf(outf,
135 "CALCMOVE: onecard(op) = %d, foundend = %d\n",
136 onecard(op), foundend);
137 #endif
138 playsafe:
139 Movetype = M_PLAY;
140 Card_no = i;
141 return;
142 }
143 oppos = opposite(pp->hand[i]);
144 if (Numseen[oppos] == Numcards[oppos] &&
145 !(pp->hand[i] == C_RIGHT_WAY &&
146 Numseen[C_LIMIT] != Numcards[C_LIMIT]))
147 goto playsafe;
148 else if (!cango
149 && (op->can_go || !pp->can_go || Topcard < Deck)) {
150 card = (Topcard - Deck) - roll(1, 10);
151 if ((!pp->mileage) != (!op->mileage))
152 card -= 7;
153 #ifdef DEBUG
154 if (Debug)
155 fprintf(outf,
156 "CALCMOVE: card = %d, DECK_SZ / 4 = %d\n",
157 card, DECK_SZ / 4);
158 #endif
159 if (card < DECK_SZ / 4)
160 goto playsafe;
161 }
162 safe--;
163 playit[i] = cango;
164 }
165 }
166 if (!pp->can_go && !is_repair(pp->battle))
167 Numneed[opposite(pp->battle)]++;
168 redoit:
169 foundlow = (cango || count[C_END_LIMIT] != 0
170 || Numseen[C_LIMIT] == Numcards[C_LIMIT]
171 || pp->safety[S_RIGHT_WAY] != S_UNKNOWN);
172 foundend = FALSE;
173 count200 = pp->nummiles[C_200];
174 badcount = 0;
175 curmax = -1;
176 curmin = 101;
177 nummin = -1;
178 nummax = -1;
179 value = valbuf;
180 for (i = 0; i < HAND_SZ; i++) {
181 card = pp->hand[i];
182 if (is_safety(card) || playit[i] == (cango != 0)) {
183 #ifdef DEBUG
184 if (Debug)
185 fprintf(outf, "CALCMOVE: switch(\"%s\")\n",
186 C_name[card]);
187 #endif
188 switch (card) {
189 case C_25: case C_50:
190 diff = End - pp->mileage;
191 /* avoid getting too close */
192 if (Topcard > Deck && cango && diff <= 100
193 && (int)diff / Value[card] > count[card]
194 && (card == C_25 || diff % 50 == 0)) {
195 if (card == C_50 && diff - 50 == 25
196 && count[C_25] > 0)
197 goto okay;
198 *value = 0;
199 if (--cango <= 0)
200 goto redoit;
201 break;
202 }
203 okay:
204 *value = (Value[card] >> 3);
205 if (pp->speed == C_LIMIT)
206 ++*value;
207 else
208 --*value;
209 if (!foundlow
210 && (card == C_50 || count[C_50] == 0)) {
211 *value = (pp->mileage ? 10 : 20);
212 foundlow = TRUE;
213 }
214 goto miles;
215 case C_200:
216 if (++count200 > 2) {
217 *value = 0;
218 break;
219 }
220 case C_75: case C_100:
221 *value = (Value[card] >> 3);
222 if (pp->speed == C_LIMIT)
223 --*value;
224 else
225 ++*value;
226 miles:
227 if (pp->mileage + Value[card] > End)
228 *value = (End == 700 ? card : 0);
229 else if (pp->mileage + Value[card] == End) {
230 *value = (foundend ? card : V_VALUABLE);
231 foundend = TRUE;
232 }
233 break;
234 case C_END_LIMIT:
235 if (pp->safety[S_RIGHT_WAY] != S_UNKNOWN)
236 *value = (pp->safety[S_RIGHT_WAY] ==
237 S_PLAYED ? -1 : 1);
238 else if (pp->speed == C_LIMIT &&
239 End - pp->mileage <= 50)
240 *value = 1;
241 else if (pp->speed == C_LIMIT
242 || Numseen[C_LIMIT] != Numcards[C_LIMIT]) {
243 safe = S_RIGHT_WAY;
244 oppos = C_LIMIT;
245 goto repair;
246 }
247 else {
248 *value = 0;
249 --count[C_END_LIMIT];
250 }
251 break;
252 case C_REPAIRS: case C_SPARE: case C_GAS:
253 safe = safety(card) - S_CONV;
254 oppos = opposite(card);
255 if (pp->safety[safe] != S_UNKNOWN)
256 *value = (pp->safety[safe] ==
257 S_PLAYED ? -1 : 1);
258 else if (pp->battle != oppos
259 && (Numseen[oppos] == Numcards[oppos] ||
260 Numseen[oppos] + count[card] >
261 Numcards[oppos])) {
262 *value = 0;
263 --count[card];
264 }
265 else {
266 repair:
267 *value = Numcards[oppos] * 6;
268 *value += Numseen[card] -
269 Numseen[oppos];
270 if (!cango)
271 *value /= (count[card]*count[card]);
272 count[card]--;
273 }
274 break;
275 case C_GO:
276 if (pp->safety[S_RIGHT_WAY] != S_UNKNOWN)
277 *value = (pp->safety[S_RIGHT_WAY] ==
278 S_PLAYED ? -1 : 2);
279 else if (pp->can_go
280 && Numgos + count[C_GO] == Numneed[C_GO]) {
281 *value = 0;
282 --count[C_GO];
283 }
284 else {
285 *value = Numneed[C_GO] * 3;
286 *value += (Numseen[C_GO] - Numgos);
287 *value /= (count[C_GO] * count[C_GO]);
288 count[C_GO]--;
289 }
290 break;
291 case C_LIMIT:
292 if (op->mileage + 50 >= End) {
293 *value = (End == 700 && !cango);
294 break;
295 }
296 if (canstop || (cango && !op->can_go))
297 *value = 1;
298 else {
299 *value = (pp->safety[S_RIGHT_WAY] !=
300 S_UNKNOWN ? 2 : 3);
301 safe = S_RIGHT_WAY;
302 oppos = C_END_LIMIT;
303 goto normbad;
304 }
305 break;
306 case C_CRASH: case C_EMPTY: case C_FLAT:
307 safe = safety(card) - S_CONV;
308 oppos = opposite(card);
309 *value = (pp->safety[safe]!=S_UNKNOWN ? 3 : 4);
310 normbad:
311 if (op->safety[safe] == S_PLAYED)
312 *value = -1;
313 else {
314 *value *= Numneed[oppos] +
315 Numseen[oppos] + 2;
316 if (!pp->mileage || foundend ||
317 onecard(op))
318 *value += 5;
319 if (op->mileage == 0 || onecard(op))
320 *value += 5;
321 if (op->speed == C_LIMIT)
322 *value -= 3;
323 if (cango &&
324 pp->safety[safe] != S_UNKNOWN)
325 *value += 3;
326 if (!cango)
327 *value /= ++badcount;
328 }
329 break;
330 case C_STOP:
331 if (op->safety[S_RIGHT_WAY] == S_PLAYED)
332 *value = -1;
333 else {
334 *value = (pp->safety[S_RIGHT_WAY] !=
335 S_UNKNOWN ? 3 : 4);
336 *value *= Numcards[C_STOP] +
337 Numseen[C_GO];
338 if (!pp->mileage || foundend ||
339 onecard(op))
340 *value += 5;
341 if (!cango)
342 *value /= ++badcount;
343 if (op->mileage == 0)
344 *value += 5;
345 if ((card == C_LIMIT &&
346 op->speed == C_LIMIT) ||
347 !op->can_go)
348 *value -= 5;
349 if (cango && pp->safety[S_RIGHT_WAY] !=
350 S_UNKNOWN)
351 *value += 5;
352 }
353 break;
354 case C_GAS_SAFE: case C_DRIVE_SAFE:
355 case C_SPARE_SAFE: case C_RIGHT_WAY:
356 *value = cango ? 0 : 101;
357 break;
358 case C_INIT:
359 *value = 0;
360 break;
361 }
362 }
363 else
364 *value = cango ? 0 : 101;
365 if (card != C_INIT) {
366 if (*value >= curmax) {
367 nummax = i;
368 curmax = *value;
369 }
370 if (*value <= curmin) {
371 nummin = i;
372 curmin = *value;
373 }
374 }
375 #ifdef DEBUG
376 if (Debug)
377 mvprintw(i + 6, 2, "%3d %-14s", *value,
378 C_name[pp->hand[i]]);
379 #endif
380 value++;
381 }
382 if (!pp->can_go && !is_repair(pp->battle))
383 Numneed[opposite(pp->battle)]++;
384 if (cango) {
385 play_it:
386 mvaddstr(MOVE_Y + 1, MOVE_X, "PLAY\n");
387 Movetype = M_PLAY;
388 Card_no = nummax;
389 }
390 else {
391 if (is_safety(pp->hand[nummin])) { /* NEVER discard a safety */
392 nummax = nummin;
393 goto play_it;
394 }
395 mvaddstr(MOVE_Y + 1, MOVE_X, "DISCARD\n");
396 Movetype = M_DISCARD;
397 Card_no = nummin;
398 }
399 mvprintw(MOVE_Y + 2, MOVE_X, "%16s", C_name[pp->hand[Card_no]]);
400 }
401
402 /*
403 * Return true if the given player could conceivably win with his next card.
404 */
405 int
406 onecard(pp)
407 const PLAY *pp;
408 {
409 CARD bat, spd, card;
410
411 bat = pp->battle;
412 spd = pp->speed;
413 card = -1;
414 if (pp->can_go || ((is_repair(bat) || bat == C_STOP || spd == C_LIMIT) &&
415 Numseen[S_RIGHT_WAY] != 0) ||
416 (bat >= 0 && Numseen[safety(bat)] != 0))
417 switch (End - pp->mileage) {
418 case 200:
419 if (pp->nummiles[C_200] == 2)
420 return FALSE;
421 card = C_200;
422 /* FALLTHROUGH */
423 case 100:
424 case 75:
425 if (card == -1)
426 card = (End - pp->mileage == 75 ? C_75 : C_100);
427 if (spd == C_LIMIT)
428 return Numseen[S_RIGHT_WAY] == 0;
429 case 50:
430 case 25:
431 if (card == -1)
432 card = (End - pp->mileage == 25 ? C_25 : C_50);
433 return Numseen[card] != Numcards[card];
434 }
435 return FALSE;
436 }
437
438 int
439 canplay(pp, op, card)
440 const PLAY *pp, *op;
441 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 (is_repair(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 }