Merge from vendor branch GDB:
[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  * @(#)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 $
36  */
37
38 # include       "mille.h"
39
40 /*
41  * @(#)comp.c   1.1 (Berkeley) 4/1/82
42  */
43
44 # define        V_VALUABLE      40
45
46 void
47 calcmove()
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);
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;
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
135 playsafe:
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)]++;
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                                     && 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                                 }
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;
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;
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;
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 {
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]--;
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);
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;
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) {
382 play_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  */
402 bool
403 onecard(pp)
404 PLAY    *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
435 bool
436 canplay(pp, op, card)
437 PLAY    *pp, *op;
438 CARD    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 }