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