dma: beautify queue listing output
[dragonfly.git] / games / mille / comp.c
blob39a37da054f28af88d138d290d16bf6e3701f3c2
1 /*
2 * Copyright (c) 1982, 1993
3 * The Regents of the University of California. All rights reserved.
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.
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.
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.4 2008/06/05 18:06:30 swildner Exp $
38 # include "mille.h"
41 * @(#)comp.c 1.1 (Berkeley) 4/1/82
44 # define V_VALUABLE 40
46 void
47 calcmove(void)
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];
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;
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)) != 0)
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);
93 norm:
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;
105 ++safe;
106 playit[i] = TRUE;
107 break;
109 if (card >= 0)
110 ++count[card];
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;
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
135 playsafe:
136 Movetype = M_PLAY;
137 Card_no = i;
138 return;
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;
159 safe--;
160 playit[i] = cango;
163 if (!pp->can_go && !isrepair(pp->battle))
164 Numneed[opposite(pp->battle)]++;
165 redoit:
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 && (int)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;
200 okay:
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;
211 goto miles;
212 case C_200:
213 if (++count200 > 2) {
214 *value = 0;
215 break;
217 case C_75: case C_100:
218 *value = (Value[card] >> 3);
219 if (pp->speed == C_LIMIT)
220 --*value;
221 else
222 ++*value;
223 miles:
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;
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;
244 else {
245 *value = 0;
246 --count[C_END_LIMIT];
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];
262 else {
263 repair:
264 *value = Numcards[oppos] * 6;
265 *value += Numseen[card] -
266 Numseen[oppos];
267 if (!cango)
268 *value /= (count[card]*count[card]);
269 count[card]--;
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];
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]--;
287 break;
288 case C_LIMIT:
289 if (op->mileage + 50 >= End) {
290 *value = (End == 700 && !cango);
291 break;
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;
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);
307 normbad:
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;
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;
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;
360 else
361 *value = cango ? 0 : 101;
362 if (card != C_INIT) {
363 if (*value >= curmax) {
364 nummax = i;
365 curmax = *value;
367 if (*value <= curmin) {
368 nummin = i;
369 curmin = *value;
372 #ifdef DEBUG
373 if (Debug)
374 mvprintw(i + 6, 2, "%3d %-14s", *value,
375 C_name[pp->hand[i]]);
376 #endif
377 value++;
379 if (!pp->can_go && !isrepair(pp->battle))
380 Numneed[opposite(pp->battle)]++;
381 if (cango) {
382 play_it:
383 mvaddstr(MOVE_Y + 1, MOVE_X, "PLAY\n");
384 Movetype = M_PLAY;
385 Card_no = nummax;
387 else {
388 if (issafety(pp->hand[nummin])) { /* NEVER discard a safety */
389 nummax = nummin;
390 goto play_it;
392 mvaddstr(MOVE_Y + 1, MOVE_X, "DISCARD\n");
393 Movetype = M_DISCARD;
394 Card_no = nummin;
396 mvprintw(MOVE_Y + 2, MOVE_X, "%16s", C_name[pp->hand[Card_no]]);
400 * Return true if the given player could conceivably win with his next card.
402 bool
403 onecard(PLAY *pp)
405 CARD bat, spd, card;
407 bat = pp->battle;
408 spd = pp->speed;
409 card = -1;
410 if (pp->can_go || ((isrepair(bat) || bat == C_STOP || spd == C_LIMIT) &&
411 Numseen[S_RIGHT_WAY] != 0) ||
412 (bat >= 0 && Numseen[safety(bat)] != 0))
413 switch (End - pp->mileage) {
414 case 200:
415 if (pp->nummiles[C_200] == 2)
416 return FALSE;
417 card = C_200;
418 /* FALLTHROUGH */
419 case 100:
420 case 75:
421 if (card == -1)
422 card = (End - pp->mileage == 75 ? C_75 : C_100);
423 if (spd == C_LIMIT)
424 return Numseen[S_RIGHT_WAY] == 0;
425 case 50:
426 case 25:
427 if (card == -1)
428 card = (End - pp->mileage == 25 ? C_25 : C_50);
429 return Numseen[card] != Numcards[card];
431 return FALSE;
434 bool
435 canplay(PLAY *pp, PLAY *op, CARD card)
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;
478 return FALSE;