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