Initial import from FreeBSD RELENG_4:
[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. 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.
32  */
33
34 #ifndef lint
35 #if 0
36 static char sccsid[] = "@(#)comp.c      8.1 (Berkeley) 5/31/93";
37 #endif
38 static const char rcsid[] =
39  "$FreeBSD: src/games/mille/comp.c,v 1.5 1999/12/12 06:17:24 billf Exp $";
40 #endif /* not lint */
41
42 # include       "mille.h"
43
44 /*
45  * @(#)comp.c   1.1 (Berkeley) 4/1/82
46  */
47
48 # define        V_VALUABLE      40
49
50 void
51 calcmove()
52 {
53         CARD            card;
54         int             *value;
55         PLAY            *pp, *op;
56         bool            foundend, cango, canstop, foundlow;
57         unsgn int       i, count200, badcount, nummin, nummax, diff;
58         int             curmin, curmax;
59         CARD            safe, oppos;
60         int                     valbuf[HAND_SZ], count[NUM_CARDS];
61         bool                    playit[HAND_SZ];
62
63         wmove(Score, ERR_Y, ERR_X);     /* get rid of error messages    */
64         wclrtoeol(Score);
65         pp = &Player[COMP];
66         op = &Player[PLAYER];
67         safe = 0;
68         cango = 0;
69         canstop = FALSE;
70         foundend = FALSE;
71
72         /* Try for a Coup Forre, and see what we have. */
73         for (i = 0; i < NUM_CARDS; i++)
74                 count[i] = 0;
75         for (i = 0; i < HAND_SZ; i++) {
76                 card = pp->hand[i];
77                 switch (card) {
78                   case C_STOP:  case C_CRASH:
79                   case C_FLAT:  case C_EMPTY:
80                         if ((playit[i] = canplay(pp, op, card)) != NULL)
81                                 canstop = TRUE;
82                         goto norm;
83                   case C_LIMIT:
84                         if ((playit[i] = canplay(pp, op, card))
85                             && Numseen[C_25] == Numcards[C_25]
86                             && Numseen[C_50] == Numcards[C_50])
87                                 canstop = TRUE;
88                         goto norm;
89                   case C_25:    case C_50:      case C_75:
90                   case C_100:   case C_200:
91                         if ((playit[i] = canplay(pp, op, card))
92                             && pp->mileage + Value[card] == End)
93                                 foundend = TRUE;
94                         goto norm;
95                   default:
96                         playit[i] = canplay(pp, op, card);
97 norm:
98                         if (playit[i])
99                                 ++cango;
100                         break;
101                   case C_GAS_SAFE:      case C_DRIVE_SAFE:
102                   case C_SPARE_SAFE:    case C_RIGHT_WAY:
103                         if (pp->battle == opposite(card) ||
104                             (pp->speed == C_LIMIT && card == C_RIGHT_WAY)) {
105                                 Movetype = M_PLAY;
106                                 Card_no = i;
107                                 return;
108                         }
109                         ++safe;
110                         playit[i] = TRUE;
111                         break;
112                 }
113                 if (card >= 0)
114                         ++count[card];
115         }
116
117         /* No Coup Forre.  Draw to fill hand, then restart, as needed. */
118         if (pp->hand[0] == C_INIT && Topcard > Deck) {
119                 Movetype = M_DRAW;
120                 return;
121         }
122
123 #ifdef DEBUG
124         if (Debug)
125                 fprintf(outf, "CALCMOVE: cango = %d, canstop = %d, safe = %d\n",
126                         cango, canstop, safe);
127 #endif
128         if (foundend)
129                 foundend = !check_ext(TRUE);
130         for (i = 0; safe && i < HAND_SZ; i++) {
131                 if (issafety(pp->hand[i])) {
132                         if (onecard(op) || (foundend && cango && !canstop)) {
133 #ifdef DEBUG
134                                 if (Debug)
135                                         fprintf(outf,
136                                                 "CALCMOVE: onecard(op) = %d, foundend = %d\n",
137                                                 onecard(op), foundend);
138 #endif
139 playsafe:
140                                 Movetype = M_PLAY;
141                                 Card_no = i;
142                                 return;
143                         }
144                         oppos = opposite(pp->hand[i]);
145                         if (Numseen[oppos] == Numcards[oppos] &&
146                             !(pp->hand[i] == C_RIGHT_WAY &&
147                               Numseen[C_LIMIT] != Numcards[C_LIMIT]))
148                                 goto playsafe;
149                         else if (!cango
150                             && (op->can_go || !pp->can_go || Topcard < Deck)) {
151                                 card = (Topcard - Deck) - roll(1, 10);
152                                 if ((!pp->mileage) != (!op->mileage))
153                                         card -= 7;
154 #ifdef DEBUG
155                                 if (Debug)
156                                         fprintf(outf,
157                                                 "CALCMOVE: card = %d, DECK_SZ / 4 = %d\n",
158                                                 card, DECK_SZ / 4);
159 #endif
160                                 if (card < DECK_SZ / 4)
161                                         goto playsafe;
162                         }
163                         safe--;
164                         playit[i] = cango;
165                 }
166         }
167         if (!pp->can_go && !isrepair(pp->battle))
168                 Numneed[opposite(pp->battle)]++;
169 redoit:
170         foundlow = (cango || count[C_END_LIMIT] != 0
171                           || Numseen[C_LIMIT] == Numcards[C_LIMIT]
172                           || pp->safety[S_RIGHT_WAY] != S_UNKNOWN);
173         foundend = FALSE;
174         count200 = pp->nummiles[C_200];
175         badcount = 0;
176         curmax = -1;
177         curmin = 101;
178         nummin = -1;
179         nummax = -1;
180         value = valbuf;
181         for (i = 0; i < HAND_SZ; i++) {
182                 card = pp->hand[i];
183                 if (issafety(card) || playit[i] == (cango != 0)) {
184 #ifdef DEBUG
185                         if (Debug)
186                                 fprintf(outf, "CALCMOVE: switch(\"%s\")\n",
187                                         C_name[card]);
188 #endif
189                         switch (card) {
190                           case C_25:    case C_50:
191                                 diff = End - pp->mileage;
192                                 /* avoid getting too close */
193                                 if (Topcard > Deck && cango && diff <= 100
194                                     && diff / Value[card] > count[card]
195                                     && (card == C_25 || diff % 50 == 0)) {
196                                         if (card == C_50 && diff - 50 == 25
197                                             && count[C_25] > 0)
198                                                 goto okay;
199                                         *value = 0;
200                                         if (--cango <= 0)
201                                                 goto redoit;
202                                         break;
203                                 }
204 okay:
205                                 *value = (Value[card] >> 3);
206                                 if (pp->speed == C_LIMIT)
207                                         ++*value;
208                                 else
209                                         --*value;
210                                 if (!foundlow
211                                    && (card == C_50 || count[C_50] == 0)) {
212                                         *value = (pp->mileage ? 10 : 20);
213                                         foundlow = TRUE;
214                                 }
215                                 goto miles;
216                           case C_200:
217                                 if (++count200 > 2) {
218                                         *value = 0;
219                                         break;
220                                 }
221                           case C_75:    case C_100:
222                                 *value = (Value[card] >> 3);
223                                 if (pp->speed == C_LIMIT)
224                                         --*value;
225                                 else
226                                         ++*value;
227 miles:
228                                 if (pp->mileage + Value[card] > End)
229                                         *value = (End == 700 ? card : 0);
230                                 else if (pp->mileage + Value[card] == End) {
231                                         *value = (foundend ? card : V_VALUABLE);
232                                         foundend = TRUE;
233                                 }
234                                 break;
235                           case C_END_LIMIT:
236                                 if (pp->safety[S_RIGHT_WAY] != S_UNKNOWN)
237                                         *value = (pp->safety[S_RIGHT_WAY] ==
238                                                   S_PLAYED ? -1 : 1);
239                                 else if (pp->speed == C_LIMIT &&
240                                          End - pp->mileage <= 50)
241                                         *value = 1;
242                                 else if (pp->speed == C_LIMIT
243                                     || Numseen[C_LIMIT] != Numcards[C_LIMIT]) {
244                                         safe = S_RIGHT_WAY;
245                                         oppos = C_LIMIT;
246                                         goto repair;
247                                 }
248                                 else {
249                                         *value = 0;
250                                         --count[C_END_LIMIT];
251                                 }
252                                 break;
253                           case C_REPAIRS:       case C_SPARE:   case C_GAS:
254                                 safe = safety(card) - S_CONV;
255                                 oppos = opposite(card);
256                                 if (pp->safety[safe] != S_UNKNOWN)
257                                         *value = (pp->safety[safe] ==
258                                                   S_PLAYED ? -1 : 1);
259                                 else if (pp->battle != oppos
260                                     && (Numseen[oppos] == Numcards[oppos] ||
261                                         Numseen[oppos] + count[card] >
262                                         Numcards[oppos])) {
263                                         *value = 0;
264                                         --count[card];
265                                 }
266                                 else {
267 repair:
268                                         *value = Numcards[oppos] * 6;
269                                         *value += Numseen[card] -
270                                                   Numseen[oppos];
271                                         if (!cango)
272                                             *value /= (count[card]*count[card]);
273                                         count[card]--;
274                                 }
275                                 break;
276                           case C_GO:
277                                 if (pp->safety[S_RIGHT_WAY] != S_UNKNOWN)
278                                         *value = (pp->safety[S_RIGHT_WAY] ==
279                                                   S_PLAYED ? -1 : 2);
280                                 else if (pp->can_go
281                                  && Numgos + count[C_GO] == Numneed[C_GO]) {
282                                         *value = 0;
283                                         --count[C_GO];
284                                 }
285                                 else {
286                                         *value = Numneed[C_GO] * 3;
287                                         *value += (Numseen[C_GO] - Numgos);
288                                         *value /= (count[C_GO] * count[C_GO]);
289                                         count[C_GO]--;
290                                 }
291                                 break;
292                           case C_LIMIT:
293                                 if (op->mileage + 50 >= End) {
294                                         *value = (End == 700 && !cango);
295                                         break;
296                                 }
297                                 if (canstop || (cango && !op->can_go))
298                                         *value = 1;
299                                 else {
300                                         *value = (pp->safety[S_RIGHT_WAY] !=
301                                                   S_UNKNOWN ? 2 : 3);
302                                         safe = S_RIGHT_WAY;
303                                         oppos = C_END_LIMIT;
304                                         goto normbad;
305                                 }
306                                 break;
307                           case C_CRASH: case C_EMPTY:   case C_FLAT:
308                                 safe = safety(card) - S_CONV;
309                                 oppos = opposite(card);
310                                 *value = (pp->safety[safe]!=S_UNKNOWN ? 3 : 4);
311 normbad:
312                                 if (op->safety[safe] == S_PLAYED)
313                                         *value = -1;
314                                 else {
315                                         *value *= Numneed[oppos] +
316                                                   Numseen[oppos] + 2;
317                                         if (!pp->mileage || foundend ||
318                                             onecard(op))
319                                                 *value += 5;
320                                         if (op->mileage == 0 || onecard(op))
321                                                 *value += 5;
322                                         if (op->speed == C_LIMIT)
323                                                 *value -= 3;
324                                         if (cango &&
325                                             pp->safety[safe] != S_UNKNOWN)
326                                                 *value += 3;
327                                         if (!cango)
328                                                 *value /= ++badcount;
329                                 }
330                                 break;
331                           case C_STOP:
332                                 if (op->safety[S_RIGHT_WAY] == S_PLAYED)
333                                         *value = -1;
334                                 else {
335                                         *value = (pp->safety[S_RIGHT_WAY] !=
336                                                   S_UNKNOWN ? 3 : 4);
337                                         *value *= Numcards[C_STOP] +
338                                                   Numseen[C_GO];
339                                         if (!pp->mileage || foundend ||
340                                             onecard(op))
341                                                 *value += 5;
342                                         if (!cango)
343                                                 *value /= ++badcount;
344                                         if (op->mileage == 0)
345                                                 *value += 5;
346                                         if ((card == C_LIMIT &&
347                                              op->speed == C_LIMIT) ||
348                                             !op->can_go)
349                                                 *value -= 5;
350                                         if (cango && pp->safety[S_RIGHT_WAY] !=
351                                                      S_UNKNOWN)
352                                                 *value += 5;
353                                 }
354                                 break;
355                           case C_GAS_SAFE:      case C_DRIVE_SAFE:
356                           case C_SPARE_SAFE:    case C_RIGHT_WAY:
357                                 *value = cango ? 0 : 101;
358                                 break;
359                           case C_INIT:
360                                 *value = 0;
361                                 break;
362                         }
363                 }
364                 else
365                         *value = cango ? 0 : 101;
366                 if (card != C_INIT) {
367                         if (*value >= curmax) {
368                                 nummax = i;
369                                 curmax = *value;
370                         }
371                         if (*value <= curmin) {
372                                 nummin = i;
373                                 curmin = *value;
374                         }
375                 }
376 #ifdef DEBUG
377                 if (Debug)
378                         mvprintw(i + 6, 2, "%3d %-14s", *value,
379                                  C_name[pp->hand[i]]);
380 #endif
381                 value++;
382         }
383         if (!pp->can_go && !isrepair(pp->battle))
384                 Numneed[opposite(pp->battle)]++;
385         if (cango) {
386 play_it:
387                 mvaddstr(MOVE_Y + 1, MOVE_X, "PLAY\n");
388                 Movetype = M_PLAY;
389                 Card_no = nummax;
390         }
391         else {
392                 if (issafety(pp->hand[nummin])) { /* NEVER discard a safety */
393                         nummax = nummin;
394                         goto play_it;
395                 }
396                 mvaddstr(MOVE_Y + 1, MOVE_X, "DISCARD\n");
397                 Movetype = M_DISCARD;
398                 Card_no = nummin;
399         }
400         mvprintw(MOVE_Y + 2, MOVE_X, "%16s", C_name[pp->hand[Card_no]]);
401 }
402
403 /*
404  * Return true if the given player could conceivably win with his next card.
405  */
406 bool
407 onecard(pp)
408 PLAY    *pp;
409 {
410         CARD    bat, spd, card;
411
412         bat = pp->battle;
413         spd = pp->speed;
414         card = -1;
415         if (pp->can_go || ((isrepair(bat) || bat == C_STOP || spd == C_LIMIT) &&
416                            Numseen[S_RIGHT_WAY] != 0) ||
417             (bat >= 0 && Numseen[safety(bat)] != 0))
418                 switch (End - pp->mileage) {
419                   case 200:
420                         if (pp->nummiles[C_200] == 2)
421                                 return FALSE;
422                         card = C_200;
423                         /* FALLTHROUGH */
424                   case 100:
425                   case 75:
426                         if (card == -1)
427                                 card = (End - pp->mileage == 75 ? C_75 : C_100);
428                         if (spd == C_LIMIT)
429                                 return Numseen[S_RIGHT_WAY] == 0;
430                   case 50:
431                   case 25:
432                         if (card == -1)
433                                 card = (End - pp->mileage == 25 ? C_25 : C_50);
434                         return Numseen[card] != Numcards[card];
435                 }
436         return FALSE;
437 }
438
439 bool
440 canplay(pp, op, card)
441 PLAY    *pp, *op;
442 CARD    card;
443 {
444         switch (card) {
445           case C_200:
446                 if (pp->nummiles[C_200] == 2)
447                         break;
448                 /* FALLTHROUGH */
449           case C_75:    case C_100:
450                 if (pp->speed == C_LIMIT)
451                         break;
452                 /* FALLTHROUGH */
453           case C_50:
454                 if (pp->mileage + Value[card] > End)
455                         break;
456                 /* FALLTHROUGH */
457           case C_25:
458                 if (pp->can_go)
459                         return TRUE;
460                 break;
461           case C_EMPTY: case C_FLAT:    case C_CRASH:
462           case C_STOP:
463                 if (op->can_go && op->safety[safety(card) - S_CONV] != S_PLAYED)
464                         return TRUE;
465                 break;
466           case C_LIMIT:
467                 if (op->speed != C_LIMIT &&
468                     op->safety[S_RIGHT_WAY] != S_PLAYED &&
469                     op->mileage + 50 < End)
470                         return TRUE;
471                 break;
472           case C_GAS:   case C_SPARE:   case C_REPAIRS:
473                 if (pp->battle == opposite(card))
474                         return TRUE;
475                 break;
476           case C_GO:
477                 if (!pp->can_go &&
478                     (isrepair(pp->battle) || pp->battle == C_STOP))
479                         return TRUE;
480                 break;
481           case C_END_LIMIT:
482                 if (pp->speed == C_LIMIT)
483                         return TRUE;
484         }
485         return FALSE;
486 }