nrelease - fix/improve livecd
[dragonfly.git] / games / mille / comp.c
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. 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.
16  *
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.
28  *
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  */
32
33 #include "mille.h"
34
35 /*
36  * @(#)comp.c   1.1 (Berkeley) 4/1/82
37  */
38
39 #define V_VALUABLE      40
40
41 void
42 calcmove(void)
43 {
44         CARD            card;
45         int             *value;
46         PLAY            *pp, *op;
47         bool            foundend, cango, canstop, foundlow;
48         unsigned int    i, count200, badcount, nummin, nummax, diff;
49         int             curmin, curmax;
50         CARD            safe, oppos;
51         int             valbuf[HAND_SZ], count[NUM_CARDS];
52         bool            playit[HAND_SZ];
53
54         wmove(Score, ERR_Y, ERR_X);     /* get rid of error messages    */
55         wclrtoeol(Score);
56         pp = &Player[COMP];
57         op = &Player[PLAYER];
58         safe = 0;
59         cango = FALSE;
60         canstop = FALSE;
61         foundend = FALSE;
62
63         /* Try for a Coup Forre, and see what we have. */
64         for (i = 0; i < NUM_CARDS; i++)
65                 count[i] = 0;
66         for (i = 0; i < HAND_SZ; i++) {
67                 card = pp->hand[i];
68                 switch (card) {
69                   case C_STOP:  case C_CRASH:
70                   case C_FLAT:  case C_EMPTY:
71                         if ((playit[i] = canplay(pp, op, card)))
72                                 canstop = TRUE;
73                         goto norm;
74                   case C_LIMIT:
75                         if ((playit[i] = canplay(pp, op, card))
76                             && Numseen[C_25] == Numcards[C_25]
77                             && Numseen[C_50] == Numcards[C_50])
78                                 canstop = TRUE;
79                         goto norm;
80                   case C_25:    case C_50:      case C_75:
81                   case C_100:   case C_200:
82                         if ((playit[i] = canplay(pp, op, card))
83                             && pp->mileage + Value[card] == End)
84                                 foundend = TRUE;
85                         goto norm;
86                   default:
87                         playit[i] = canplay(pp, op, card);
88 norm:
89                         if (playit[i])
90                                 cango = TRUE;
91                         break;
92                   case C_GAS_SAFE:      case C_DRIVE_SAFE:
93                   case C_SPARE_SAFE:    case C_RIGHT_WAY:
94                         if (pp->battle == opposite(card) ||
95                             (pp->speed == C_LIMIT && card == C_RIGHT_WAY)) {
96                                 Movetype = M_PLAY;
97                                 Card_no = i;
98                                 return;
99                         }
100                         ++safe;
101                         playit[i] = TRUE;
102                         break;
103                 }
104                 if (card >= 0)
105                         ++count[card];
106         }
107
108         /* No Coup Forre.  Draw to fill hand, then restart, as needed. */
109         if (pp->hand[0] == C_INIT && Topcard > Deck) {
110                 Movetype = M_DRAW;
111                 return;
112         }
113
114 #ifdef DEBUG
115         if (Debug)
116                 fprintf(outf, "CALCMOVE: cango = %d, canstop = %d, safe = %d\n",
117                         cango, canstop, safe);
118 #endif
119         if (foundend)
120                 foundend = !check_ext(TRUE);
121         for (i = 0; safe && i < HAND_SZ; i++) {
122                 if (issafety(pp->hand[i])) {
123                         if (onecard(op) || (foundend && cango && !canstop)) {
124 #ifdef DEBUG
125                                 if (Debug)
126                                         fprintf(outf,
127                                                 "CALCMOVE: onecard(op) = %d, foundend = %d\n",
128                                                 onecard(op), foundend);
129 #endif
130 playsafe:
131                                 Movetype = M_PLAY;
132                                 Card_no = i;
133                                 return;
134                         }
135                         oppos = opposite(pp->hand[i]);
136                         if (Numseen[oppos] == Numcards[oppos] &&
137                             !(pp->hand[i] == C_RIGHT_WAY &&
138                               Numseen[C_LIMIT] != Numcards[C_LIMIT]))
139                                 goto playsafe;
140                         else if (!cango
141                             && (op->can_go || !pp->can_go || Topcard < Deck)) {
142                                 card = (Topcard - Deck) - roll(1, 10);
143                                 if ((!pp->mileage) != (!op->mileage))
144                                         card -= 7;
145 #ifdef DEBUG
146                                 if (Debug)
147                                         fprintf(outf,
148                                                 "CALCMOVE: card = %d, DECK_SZ / 4 = %d\n",
149                                                 card, DECK_SZ / 4);
150 #endif
151                                 if (card < DECK_SZ / 4)
152                                         goto playsafe;
153                         }
154                         safe--;
155                         playit[i] = cango;
156                 }
157         }
158         if (!pp->can_go && !isrepair(pp->battle))
159                 Numneed[opposite(pp->battle)]++;
160 redoit:
161         foundlow = (cango || count[C_END_LIMIT] != 0
162                           || Numseen[C_LIMIT] == Numcards[C_LIMIT]
163                           || pp->safety[S_RIGHT_WAY] != S_UNKNOWN);
164         foundend = FALSE;
165         count200 = pp->nummiles[C_200];
166         badcount = 0;
167         curmax = -1;
168         curmin = 101;
169         nummin = -1;
170         nummax = -1;
171         value = valbuf;
172         for (i = 0; i < HAND_SZ; i++) {
173                 card = pp->hand[i];
174                 if (issafety(card) || playit[i] == cango) {
175 #ifdef DEBUG
176                         if (Debug)
177                                 fprintf(outf, "CALCMOVE: switch(\"%s\")\n",
178                                         C_name[card]);
179 #endif
180                         switch (card) {
181                           case C_25:    case C_50:
182                                 diff = End - pp->mileage;
183                                 /* avoid getting too close */
184                                 if (Topcard > Deck && cango && diff <= 100
185                                     && (int)diff / Value[card] > count[card]
186                                     && (card == C_25 || diff % 50 == 0)) {
187                                         if (card == C_50 && diff - 50 == 25
188                                             && count[C_25] > 0)
189                                                 goto okay;
190                                         *value = 0;
191                                         cango = FALSE;
192                                         goto redoit;
193                                 }
194 okay:
195                                 *value = (Value[card] >> 3);
196                                 if (pp->speed == C_LIMIT)
197                                         ++*value;
198                                 else
199                                         --*value;
200                                 if (!foundlow
201                                    && (card == C_50 || count[C_50] == 0)) {
202                                         *value = (pp->mileage ? 10 : 20);
203                                         foundlow = TRUE;
204                                 }
205                                 goto miles;
206                           case C_200:
207                                 if (++count200 > 2) {
208                                         *value = 0;
209                                         break;
210                                 }
211                                 /* FALLTHROUGH */
212                           case C_100:
213                           case C_75:
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;
225                                 }
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;
239                                 }
240                                 else {
241                                         *value = 0;
242                                         --count[C_END_LIMIT];
243                                 }
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];
257                                 }
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]--;
266                                 }
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];
276                                 }
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]--;
282                                 }
283                                 break;
284                           case C_LIMIT:
285                                 if (op->mileage + 50 >= End) {
286                                         *value = (End == 700 && !cango);
287                                         break;
288                                 }
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;
297                                 }
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;
321                                 }
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;
345                                 }
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;
354                         }
355                 }
356                 else
357                         *value = cango ? 0 : 101;
358                 if (card != C_INIT) {
359                         if (*value >= curmax) {
360                                 nummax = i;
361                                 curmax = *value;
362                         }
363                         if (*value <= curmin) {
364                                 nummin = i;
365                                 curmin = *value;
366                         }
367                 }
368 #ifdef DEBUG
369                 if (Debug)
370                         mvprintw(i + 6, 2, "%3d %-14s", *value,
371                                  C_name[pp->hand[i]]);
372 #endif
373                 value++;
374         }
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;
382         }
383         else {
384                 if (issafety(pp->hand[nummin])) { /* NEVER discard a safety */
385                         nummax = nummin;
386                         goto play_it;
387                 }
388                 mvaddstr(MOVE_Y + 1, MOVE_X, "DISCARD\n");
389                 Movetype = M_DISCARD;
390                 Card_no = nummin;
391         }
392         mvprintw(MOVE_Y + 2, MOVE_X, "%16s", C_name[pp->hand[Card_no]]);
393 }
394
395 /*
396  * Return true if the given player could conceivably win with his next card.
397  */
398 bool
399 onecard(const PLAY *pp)
400 {
401         CARD    bat, spd, card;
402
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                         /* FALLTHROUGH */
422                   case 50:
423                   case 25:
424                         if (card == -1)
425                                 card = (End - pp->mileage == 25 ? C_25 : C_50);
426                         return Numseen[card] != Numcards[card];
427                 }
428         return FALSE;
429 }
430
431 bool
432 canplay(const PLAY *pp, const PLAY *op, CARD card)
433 {
434         switch (card) {
435           case C_200:
436                 if (pp->nummiles[C_200] == 2)
437                         break;
438                 /* FALLTHROUGH */
439           case C_75:    case C_100:
440                 if (pp->speed == C_LIMIT)
441                         break;
442                 /* FALLTHROUGH */
443           case C_50:
444                 if (pp->mileage + Value[card] > End)
445                         break;
446                 /* FALLTHROUGH */
447           case C_25:
448                 if (pp->can_go)
449                         return TRUE;
450                 break;
451           case C_EMPTY: case C_FLAT:    case C_CRASH:
452           case C_STOP:
453                 if (op->can_go && op->safety[safety(card) - S_CONV] != S_PLAYED)
454                         return TRUE;
455                 break;
456           case C_LIMIT:
457                 if (op->speed != C_LIMIT &&
458                     op->safety[S_RIGHT_WAY] != S_PLAYED &&
459                     op->mileage + 50 < End)
460                         return TRUE;
461                 break;
462           case C_GAS:   case C_SPARE:   case C_REPAIRS:
463                 if (pp->battle == opposite(card))
464                         return TRUE;
465                 break;
466           case C_GO:
467                 if (!pp->can_go &&
468                     (isrepair(pp->battle) || pp->battle == C_STOP))
469                         return TRUE;
470                 break;
471           case C_END_LIMIT:
472                 if (pp->speed == C_LIMIT)
473                         return TRUE;
474         }
475         return FALSE;
476 }