date and time created 88/07/22 16:08:01 by bostic
[unix-history] / usr / src / games / mille / comp.c
CommitLineData
f1f29fdb
KB
1/*
2 * Copyright (c) 1982 Regents of the University of California.
1b2b6de1
KB
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms are permitted
65c7d3b6
KB
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * advertising materials, and other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by the University of California, Berkeley. The name of the
11 * University may not be used to endorse or promote products derived
12 * from this software without specific prior written permission.
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
f1f29fdb
KB
16 */
17
18#ifndef lint
65c7d3b6 19static char sccsid[] = "@(#)comp.c 5.3 (Berkeley) %G%";
1b2b6de1 20#endif /* not lint */
f1f29fdb
KB
21
22# include "mille.h"
23
24/*
25 * @(#)comp.c 1.1 (Berkeley) 4/1/82
26 */
27
28# define V_VALUABLE 40
29
30calcmove()
31{
32 register CARD card;
33 register int *value;
34 register PLAY *pp, *op;
35 register bool foundend, cango, canstop, foundlow;
36 register unsgn int i, count200, badcount, nummin, nummax, diff;
37 register int curmin, curmax;
38 register CARD safe, oppos;
39 int valbuf[HAND_SZ], count[NUM_CARDS];
40 bool playit[HAND_SZ];
41
42 wmove(Score, ERR_Y, ERR_X); /* get rid of error messages */
43 wclrtoeol(Score);
44 pp = &Player[COMP];
45 op = &Player[PLAYER];
46 safe = 0;
47 cango = 0;
48 canstop = FALSE;
49 foundend = FALSE;
50 for (i = 0; i < NUM_CARDS; i++)
51 count[i] = 0;
52 for (i = 0; i < HAND_SZ; i++) {
53 card = pp->hand[i];
54 switch (card) {
55 case C_STOP: case C_CRASH:
56 case C_FLAT: case C_EMPTY:
57 if (playit[i] = canplay(pp, op, card))
58 canstop = TRUE;
59 goto norm;
60 case C_LIMIT:
61 if ((playit[i] = canplay(pp, op, card))
62 && Numseen[C_25] == Numcards[C_25]
63 && Numseen[C_50] == Numcards[C_50])
64 canstop = TRUE;
65 goto norm;
66 case C_25: case C_50: case C_75:
67 case C_100: case C_200:
68 if ((playit[i] = canplay(pp, op, card))
69 && pp->mileage + Value[card] == End)
70 foundend = TRUE;
71 goto norm;
72 default:
73 playit[i] = canplay(pp, op, card);
74norm:
75 if (playit[i])
76 ++cango;
77 break;
78 case C_GAS_SAFE: case C_DRIVE_SAFE:
79 case C_SPARE_SAFE: case C_RIGHT_WAY:
80 if (pp->battle == opposite(card) ||
81 (pp->speed == C_LIMIT && card == C_RIGHT_WAY)) {
82 Movetype = M_PLAY;
83 Card_no = i;
84 return;
85 }
86 ++safe;
87 playit[i] = TRUE;
88 break;
89 }
90 ++count[card];
91 }
92 if (pp->hand[0] == C_INIT && Topcard > Deck) {
93 Movetype = M_DRAW;
94 return;
95 }
1b2b6de1 96#ifdef DEBUG
f1f29fdb
KB
97 if (Debug)
98 fprintf(outf, "CALCMOVE: cango = %d, canstop = %d, safe = %d\n",
99 cango, canstop, safe);
1b2b6de1 100#endif
f1f29fdb
KB
101 if (foundend)
102 foundend = !check_ext(TRUE);
103 for (i = 0; safe && i < HAND_SZ; i++) {
104 if (issafety(pp->hand[i])) {
105 if (onecard(op) || (foundend && cango && !canstop)) {
1b2b6de1 106#ifdef DEBUG
f1f29fdb
KB
107 if (Debug)
108 fprintf(outf,
109 "CALCMOVE: onecard(op) = %d, foundend = %d\n",
110 onecard(op), foundend);
1b2b6de1 111#endif
f1f29fdb
KB
112playsafe:
113 Movetype = M_PLAY;
114 Card_no = i;
115 return;
116 }
117 oppos = opposite(pp->hand[i]);
118 if (Numseen[oppos] == Numcards[oppos] &&
119 !(pp->hand[i] == C_RIGHT_WAY &&
120 Numseen[C_LIMIT] != Numcards[C_LIMIT]))
121 goto playsafe;
122 else if (!cango
123 && (op->can_go || !pp->can_go || Topcard < Deck)) {
124 card = (Topcard - Deck) - roll(1, 10);
125 if ((!pp->mileage) != (!op->mileage))
126 card -= 7;
1b2b6de1 127#ifdef DEBUG
f1f29fdb
KB
128 if (Debug)
129 fprintf(outf,
130 "CALCMOVE: card = %d, DECK_SZ / 4 = %d\n",
131 card, DECK_SZ / 4);
1b2b6de1 132#endif
f1f29fdb
KB
133 if (card < DECK_SZ / 4)
134 goto playsafe;
135 }
136 safe--;
137 playit[i] = cango;
138 }
139 }
140 if (!pp->can_go && !isrepair(pp->battle))
141 Numneed[opposite(pp->battle)]++;
142redoit:
143 foundlow = (cango || count[C_END_LIMIT] != 0
144 || Numseen[C_LIMIT] == Numcards[C_LIMIT]
145 || pp->safety[S_RIGHT_WAY] != S_UNKNOWN);
146 foundend = FALSE;
147 count200 = pp->nummiles[C_200];
148 badcount = 0;
149 curmax = -1;
150 curmin = 101;
151 nummin = -1;
152 nummax = -1;
153 value = valbuf;
154 for (i = 0; i < HAND_SZ; i++) {
155 card = pp->hand[i];
156 if (issafety(card) || playit[i] == (cango != 0)) {
1b2b6de1 157#ifdef DEBUG
f1f29fdb
KB
158 if (Debug)
159 fprintf(outf, "CALCMOVE: switch(\"%s\")\n",
160 C_name[card]);
1b2b6de1 161#endif
f1f29fdb
KB
162 switch (card) {
163 case C_25: case C_50:
164 diff = End - pp->mileage;
165 /* avoid getting too close */
166 if (Topcard > Deck && cango && diff <= 100
167 && diff / Value[card] > count[card]
168 && (card == C_25 || diff % 50 == 0)) {
169 if (card == C_50 && diff - 50 == 25
170 && count[C_25] > 0)
171 goto okay;
172 *value = 0;
173 if (--cango <= 0)
174 goto redoit;
175 break;
176 }
177okay:
178 *value = (Value[card] >> 3);
179 if (pp->speed == C_LIMIT)
180 ++*value;
181 else
182 --*value;
183 if (!foundlow
184 && (card == C_50 || count[C_50] == 0)) {
185 *value = (pp->mileage ? 10 : 20);
186 foundlow = TRUE;
187 }
188 goto miles;
189 case C_200:
190 if (++count200 > 2) {
191 *value = 0;
192 break;
193 }
194 case C_75: case C_100:
195 *value = (Value[card] >> 3);
196 if (pp->speed == C_LIMIT)
197 --*value;
198 else
199 ++*value;
200miles:
201 if (pp->mileage + Value[card] > End)
202 *value = (End == 700 ? card : 0);
203 else if (pp->mileage + Value[card] == End) {
204 *value = (foundend ? card : V_VALUABLE);
205 foundend = TRUE;
206 }
207 break;
208 case C_END_LIMIT:
209 if (pp->safety[S_RIGHT_WAY] != S_UNKNOWN)
210 *value = (pp->safety[S_RIGHT_WAY] ==
211 S_PLAYED ? -1 : 1);
212 else if (pp->speed == C_LIMIT &&
213 End - pp->mileage <= 50)
214 *value = 1;
215 else if (pp->speed == C_LIMIT
216 || Numseen[C_LIMIT] != Numcards[C_LIMIT]) {
217 safe = S_RIGHT_WAY;
218 oppos = C_LIMIT;
219 goto repair;
220 }
221 else {
222 *value = 0;
223 --count[C_END_LIMIT];
224 }
225 break;
226 case C_REPAIRS: case C_SPARE: case C_GAS:
227 safe = safety(card) - S_CONV;
228 oppos = opposite(card);
229 if (pp->safety[safe] != S_UNKNOWN)
230 *value = (pp->safety[safe] ==
231 S_PLAYED ? -1 : 1);
232 else if (pp->battle != oppos
233 && (Numseen[oppos] == Numcards[oppos] ||
234 Numseen[oppos] + count[card] >
235 Numcards[oppos])) {
236 *value = 0;
237 --count[card];
238 }
239 else {
240repair:
241 *value = Numcards[oppos] * 6;
242 *value += Numseen[card] -
243 Numseen[oppos];
244 if (!cango)
245 *value /= (count[card]*count[card]);
246 count[card]--;
247 }
248 break;
249 case C_GO:
250 if (pp->safety[S_RIGHT_WAY] != S_UNKNOWN)
251 *value = (pp->safety[S_RIGHT_WAY] ==
252 S_PLAYED ? -1 : 2);
253 else if (pp->can_go
254 && Numgos + count[C_GO] == Numneed[C_GO]) {
255 *value = 0;
256 --count[C_GO];
257 }
258 else {
259 *value = Numneed[C_GO] * 3;
260 *value += (Numseen[C_GO] - Numgos);
261 *value /= (count[C_GO] * count[C_GO]);
262 count[C_GO]--;
263 }
264 break;
265 case C_LIMIT:
266 if (op->mileage + 50 >= End) {
267 *value = (End == 700 && !cango);
268 break;
269 }
270 if (canstop || (cango && !op->can_go))
271 *value = 1;
272 else {
273 *value = (pp->safety[S_RIGHT_WAY] !=
274 S_UNKNOWN ? 2 : 3);
275 safe = S_RIGHT_WAY;
276 oppos = C_END_LIMIT;
277 goto normbad;
278 }
279 break;
280 case C_CRASH: case C_EMPTY: case C_FLAT:
281 safe = safety(card) - S_CONV;
282 oppos = opposite(card);
283 *value = (pp->safety[safe]!=S_UNKNOWN ? 3 : 4);
284normbad:
285 if (op->safety[safe] == S_PLAYED)
286 *value = -1;
287 else {
288 *value *= Numneed[oppos] +
289 Numseen[oppos] + 2;
290 if (!pp->mileage || foundend ||
291 onecard(op))
292 *value += 5;
293 if (op->mileage == 0 || onecard(op))
294 *value += 5;
295 if (op->speed == C_LIMIT)
296 *value -= 3;
297 if (cango &&
298 pp->safety[safe] != S_UNKNOWN)
299 *value += 3;
300 if (!cango)
301 *value /= ++badcount;
302 }
303 break;
304 case C_STOP:
305 if (op->safety[S_RIGHT_WAY] == S_PLAYED)
306 *value = -1;
307 else {
308 *value = (pp->safety[S_RIGHT_WAY] !=
309 S_UNKNOWN ? 3 : 4);
310 *value *= Numcards[C_STOP] +
311 Numseen[C_GO];
312 if (!pp->mileage || foundend ||
313 onecard(op))
314 *value += 5;
315 if (!cango)
316 *value /= ++badcount;
317 if (op->mileage == 0)
318 *value += 5;
319 if ((card == C_LIMIT &&
320 op->speed == C_LIMIT) ||
321 !op->can_go)
322 *value -= 5;
323 if (cango && pp->safety[S_RIGHT_WAY] !=
324 S_UNKNOWN)
325 *value += 5;
326 }
327 break;
328 case C_GAS_SAFE: case C_DRIVE_SAFE:
329 case C_SPARE_SAFE: case C_RIGHT_WAY:
330 *value = cango ? 0 : 101;
331 break;
332 case C_INIT:
333 *value = 0;
334 break;
335 }
336 }
337 else
338 *value = cango ? 0 : 101;
339 if (card != C_INIT) {
340 if (*value >= curmax) {
341 nummax = i;
342 curmax = *value;
343 }
344 if (*value <= curmin) {
345 nummin = i;
346 curmin = *value;
347 }
348 }
1b2b6de1 349#ifdef DEBUG
f1f29fdb
KB
350 if (Debug)
351 mvprintw(i + 6, 2, "%3d %-14s", *value,
352 C_name[pp->hand[i]]);
1b2b6de1 353#endif
f1f29fdb
KB
354 value++;
355 }
356 if (!pp->can_go && !isrepair(pp->battle))
357 Numneed[opposite(pp->battle)]++;
358 if (cango) {
359play_it:
360 mvaddstr(MOVE_Y + 1, MOVE_X, "PLAY\n");
1b2b6de1 361#ifdef DEBUG
f1f29fdb
KB
362 if (Debug)
363 getmove();
364 if (!Debug || Movetype == M_DRAW) {
1b2b6de1
KB
365#else
366 if (Movetype == M_DRAW) {
367#endif
f1f29fdb
KB
368 Movetype = M_PLAY;
369 Card_no = nummax;
370 }
371 }
372 else {
373 if (issafety(pp->hand[nummin])) { /* NEVER discard a safety */
374 nummax = nummin;
375 goto play_it;
376 }
377 mvaddstr(MOVE_Y + 1, MOVE_X, "DISCARD\n");
1b2b6de1 378#ifdef DEBUG
f1f29fdb
KB
379 if (Debug)
380 getmove();
381 if (!Debug || Movetype == M_DRAW) {
1b2b6de1
KB
382#else
383 if (Movetype == M_DRAW) {
384#endif
f1f29fdb
KB
385 Movetype = M_DISCARD;
386 Card_no = nummin;
387 }
388 }
389 mvprintw(MOVE_Y + 2, MOVE_X, "%16s", C_name[pp->hand[Card_no]]);
390}
391
392onecard(pp)
393register PLAY *pp;
394{
395 register CARD bat, spd, card;
396
397 bat = pp->battle;
398 spd = pp->speed;
399 card = -1;
400 if (pp->can_go || ((isrepair(bat) || bat == C_STOP || spd == C_LIMIT) &&
401 Numseen[S_RIGHT_WAY] != 0) ||
402 Numseen[safety(bat)] != 0)
403 switch (End - pp->mileage) {
404 case 200:
405 if (pp->nummiles[C_200] == 2)
406 return FALSE;
407 card = C_200;
408 /* FALLTHROUGH */
409 case 100:
410 case 75:
411 if (card == -1)
412 card = (End - pp->mileage == 75 ? C_75 : C_100);
413 if (spd == C_LIMIT)
414 return Numseen[S_RIGHT_WAY] == 0;
415 case 50:
416 case 25:
417 if (card == -1)
418 card = (End - pp->mileage == 25 ? C_25 : C_50);
419 return Numseen[card] != Numcards[card];
420 }
421 return FALSE;
422}
423
424canplay(pp, op, card)
425register PLAY *pp, *op;
426register CARD card;
427{
428 switch (card) {
429 case C_200:
430 if (pp->nummiles[C_200] == 2)
431 break;
432 /* FALLTHROUGH */
433 case C_75: case C_100:
434 if (pp->speed == C_LIMIT)
435 break;
436 /* FALLTHROUGH */
437 case C_50:
438 if (pp->mileage + Value[card] > End)
439 break;
440 /* FALLTHROUGH */
441 case C_25:
442 if (pp->can_go)
443 return TRUE;
444 break;
445 case C_EMPTY: case C_FLAT: case C_CRASH:
446 case C_STOP:
447 if (op->can_go && op->safety[safety(card) - S_CONV] != S_PLAYED)
448 return TRUE;
449 break;
450 case C_LIMIT:
451 if (op->speed != C_LIMIT &&
452 op->safety[S_RIGHT_WAY] != S_PLAYED &&
453 op->mileage + 50 < End)
454 return TRUE;
455 break;
456 case C_GAS: case C_SPARE: case C_REPAIRS:
457 if (pp->battle == opposite(card))
458 return TRUE;
459 break;
460 case C_GO:
461 if (!pp->can_go &&
462 (isrepair(pp->battle) || pp->battle == C_STOP))
463 return TRUE;
464 break;
465 case C_END_LIMIT:
466 if (pp->speed == C_LIMIT)
467 return TRUE;
468 }
469 return FALSE;
470}