Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[dragonfly.git] / games / mille / comp.c
CommitLineData
984263bc
MD
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.
1de703da
MD
32 *
33 * @(#)comp.c 8.1 (Berkeley) 5/31/93
34 * $FreeBSD: src/games/mille/comp.c,v 1.5 1999/12/12 06:17:24 billf Exp $
35 * $DragonFly: src/games/mille/comp.c,v 1.2 2003/06/17 04:25:24 dillon Exp $
984263bc
MD
36 */
37
984263bc
MD
38# include "mille.h"
39
40/*
41 * @(#)comp.c 1.1 (Berkeley) 4/1/82
42 */
43
44# define V_VALUABLE 40
45
46void
47calcmove()
48{
49 CARD card;
50 int *value;
51 PLAY *pp, *op;
52 bool foundend, cango, canstop, foundlow;
53 unsgn int i, count200, badcount, nummin, nummax, diff;
54 int curmin, curmax;
55 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)) != NULL)
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 */
402bool
403onecard(pp)
404PLAY *pp;
405{
406 CARD bat, spd, card;
407
408 bat = pp->battle;
409 spd = pp->speed;
410 card = -1;
411 if (pp->can_go || ((isrepair(bat) || bat == C_STOP || spd == C_LIMIT) &&
412 Numseen[S_RIGHT_WAY] != 0) ||
413 (bat >= 0 && Numseen[safety(bat)] != 0))
414 switch (End - pp->mileage) {
415 case 200:
416 if (pp->nummiles[C_200] == 2)
417 return FALSE;
418 card = C_200;
419 /* FALLTHROUGH */
420 case 100:
421 case 75:
422 if (card == -1)
423 card = (End - pp->mileage == 75 ? C_75 : C_100);
424 if (spd == C_LIMIT)
425 return Numseen[S_RIGHT_WAY] == 0;
426 case 50:
427 case 25:
428 if (card == -1)
429 card = (End - pp->mileage == 25 ? C_25 : C_50);
430 return Numseen[card] != Numcards[card];
431 }
432 return FALSE;
433}
434
435bool
436canplay(pp, op, card)
437PLAY *pp, *op;
438CARD card;
439{
440 switch (card) {
441 case C_200:
442 if (pp->nummiles[C_200] == 2)
443 break;
444 /* FALLTHROUGH */
445 case C_75: case C_100:
446 if (pp->speed == C_LIMIT)
447 break;
448 /* FALLTHROUGH */
449 case C_50:
450 if (pp->mileage + Value[card] > End)
451 break;
452 /* FALLTHROUGH */
453 case C_25:
454 if (pp->can_go)
455 return TRUE;
456 break;
457 case C_EMPTY: case C_FLAT: case C_CRASH:
458 case C_STOP:
459 if (op->can_go && op->safety[safety(card) - S_CONV] != S_PLAYED)
460 return TRUE;
461 break;
462 case C_LIMIT:
463 if (op->speed != C_LIMIT &&
464 op->safety[S_RIGHT_WAY] != S_PLAYED &&
465 op->mileage + 50 < End)
466 return TRUE;
467 break;
468 case C_GAS: case C_SPARE: case C_REPAIRS:
469 if (pp->battle == opposite(card))
470 return TRUE;
471 break;
472 case C_GO:
473 if (!pp->can_go &&
474 (isrepair(pp->battle) || pp->battle == C_STOP))
475 return TRUE;
476 break;
477 case C_END_LIMIT:
478 if (pp->speed == C_LIMIT)
479 return TRUE;
480 }
481 return FALSE;
482}