BSD 4_1c_2 release
[unix-history] / usr / src / games / mille / move.c
CommitLineData
e804469b
C
1#ifndef lint
2static char sccsid[] = "@(#)move.c 4.1 12/24/82";
3#endif
4
8dd2ca95
C
5#include "mille.h"
6#include "unctrl.h"
7
8dd2ca95
C
8char *Movenames[] = {
9 "M_DISCARD", "M_DRAW", "M_PLAY", "M_ORDER"
10 };
11
12domove()
13{
14 reg PLAY *pp;
15 reg int i, j;
16 reg bool goodplay;
17
18 pp = &Player[Play];
19 if (Play == PLAYER)
20 getmove();
21 else
22 calcmove();
23 Next = FALSE;
24 goodplay = TRUE;
25 switch (Movetype) {
26 case M_DISCARD:
27 if (haspicked(pp)) {
28 if (pp->hand[Card_no] == C_INIT)
29 if (Card_no == 6)
30 Finished = TRUE;
31 else
32 error("no card there");
33 else {
34 Discard = pp->hand[Card_no];
35 pp->hand[Card_no] = C_INIT;
36 Next = TRUE;
37 if (Play == PLAYER)
38 account(Discard);
39 }
40 }
41 else
42 error("must pick first");
43 break;
44 case M_PLAY:
45 goodplay = playcard(pp);
46 break;
47 case M_DRAW:
48 Card_no = 0;
49 if (Topcard <= Deck)
50 error("no more cards");
51 else if (haspicked(pp))
52 error("already picked");
53 else {
54 pp->hand[0] = *--Topcard;
55 if (Debug)
56 fprintf(outf, "DOMOVE: Draw %s\n", C_name[*Topcard]);
57acc:
58 if (Play == COMP) {
59 account(*Topcard);
60 if (issafety(*Topcard))
61 pp->safety[*Topcard-S_CONV] = S_IN_HAND;
62 }
63 if (pp->hand[1] == C_INIT && Topcard > Deck) {
64 Card_no = 1;
65 pp->hand[1] = *--Topcard;
66 if (Debug)
67 fprintf(outf, "DOMOVE: Draw %s\n", C_name[*Topcard]);
68 goto acc;
69 }
70 pp->new_battle = FALSE;
71 pp->new_speed = FALSE;
72 }
73 break;
74
75 case M_ORDER:
76 break;
77 }
78 /*
79 * move blank card to top by one of two methods. If the
80 * computer's hand was sorted, the randomness for picking
81 * between equally valued cards would be lost
82 */
83 if (Order && Movetype != M_DRAW && goodplay && pp == &Player[PLAYER])
84 sort(pp->hand);
85 else
86 for (i = 1; i < HAND_SZ; i++)
87 if (pp->hand[i] == C_INIT) {
88 for (j = 0; pp->hand[j] == C_INIT; j++)
89 if (j >= HAND_SZ) {
90 j = 0;
91 break;
92 }
93 pp->hand[i] = pp->hand[j];
94 pp->hand[j] = C_INIT;
95 }
96 if (Topcard <= Deck)
97 check_go();
98 if (Next)
99 nextplay();
100}
101
102/*
103 * Check and see if either side can go. If they cannot,
104 * the game is over
105 */
106check_go() {
107
108 reg CARD card;
109 reg PLAY *pp, *op;
110 reg int i;
111
112 for (pp = Player; pp < &Player[2]; pp++) {
113 op = (pp == &Player[COMP] ? &Player[PLAYER] : &Player[COMP]);
114 for (i = 0; i < HAND_SZ; i++) {
115 card = pp->hand[i];
116 if (issafety(card) || canplay(pp, op, card)) {
117 if (Debug) {
118 fprintf(outf, "CHECK_GO: can play %s (%d), ", C_name[card], card);
119 fprintf(outf, "issafety(card) = %d, ", issafety(card));
120 fprintf(outf, "canplay(pp, op, card) = %d\n", canplay(pp, op, card));
121 }
122 return;
123 }
124 else if (Debug)
125 fprintf(outf, "CHECK_GO: cannot play %s\n",
126 C_name[card]);
127 }
128 }
129 Finished = TRUE;
130}
131
132playcard(pp)
133reg PLAY *pp;
134{
135 reg int v;
136 reg CARD card;
137
138 /*
139 * check and see if player has picked
140 */
141 switch (pp->hand[Card_no]) {
142 default:
143 if (!haspicked(pp))
144mustpick:
145 return error("must pick first");
146 case C_GAS_SAFE: case C_SPARE_SAFE:
147 case C_DRIVE_SAFE: case C_RIGHT_WAY:
148 break;
149 }
150
151 card = pp->hand[Card_no];
152 if (Debug)
153 fprintf(outf, "PLAYCARD: Card = %s\n", C_name[card]);
154 Next = FALSE;
155 switch (card) {
156 case C_200:
157 if (pp->nummiles[C_200] == 2)
158 return error("only two 200's per hand");
159 case C_100: case C_75:
160 if (pp->speed == C_LIMIT)
161 return error("limit of 50");
162 case C_50:
163 if (pp->mileage + Value[card] > End)
164 return error("puts you over %d", End);
165 case C_25:
166 if (!pp->can_go)
167 return error("cannot move now");
168 pp->nummiles[card]++;
169 v = Value[card];
170 pp->total += v;
171 pp->hand_tot += v;
172 if ((pp->mileage += v) == End)
173 check_ext(FALSE);
174 break;
175
176 case C_GAS: case C_SPARE: case C_REPAIRS:
177 if (pp->battle != opposite(card))
178 return error("can't play \"%s\"", C_name[card]);
179 pp->battle = card;
180 if (pp->safety[S_RIGHT_WAY] == S_PLAYED)
181 pp->can_go = TRUE;
182 break;
183
184 case C_GO:
185 if (pp->battle != C_INIT && pp->battle != C_STOP
186 && !isrepair(pp->battle))
187 return error("cannot play \"Go\" on a \"%s\"",
188 C_name[pp->battle]);
189 pp->battle = C_GO;
190 pp->can_go = TRUE;
191 break;
192
193 case C_END_LIMIT:
194 if (pp->speed != C_LIMIT)
195 return error("not limited");
196 pp->speed = C_END_LIMIT;
197 break;
198
199 case C_EMPTY: case C_FLAT: case C_CRASH:
200 case C_STOP:
201 pp = &Player[other(Play)];
202 if (!pp->can_go)
203 return error("opponent cannot go");
204 else if (pp->safety[safety(card) - S_CONV] == S_PLAYED)
205protected:
206 return error("opponent is protected");
207 pp->battle = card;
208 pp->new_battle = TRUE;
209 pp->can_go = FALSE;
210 pp = &Player[Play];
211 break;
212
213 case C_LIMIT:
214 pp = &Player[other(Play)];
215 if (pp->speed == C_LIMIT)
216 return error("opponent has limit");
217 if (pp->safety[S_RIGHT_WAY] == S_PLAYED)
218 goto protected;
219 pp->speed = C_LIMIT;
220 pp->new_speed = TRUE;
221 pp = &Player[Play];
222 break;
223
224 case C_GAS_SAFE: case C_SPARE_SAFE:
225 case C_DRIVE_SAFE: case C_RIGHT_WAY:
226 if (pp->battle == opposite(card)
227 || (card == C_RIGHT_WAY && pp->speed == C_LIMIT)) {
228 if (!(card == C_RIGHT_WAY && !isrepair(pp->battle))) {
229 pp->battle = C_GO;
230 pp->can_go = TRUE;
231 }
232 if (card == C_RIGHT_WAY && pp->speed == C_LIMIT)
233 pp->speed = C_INIT;
234 if (pp->new_battle
235 || (pp->new_speed && card == C_RIGHT_WAY)) {
236 pp->coups[card - S_CONV] = TRUE;
237 pp->total += SC_COUP;
238 pp->hand_tot += SC_COUP;
239 pp->coupscore += SC_COUP;
240 }
241 }
242 /*
243 * if not coup, must pick first
244 */
245 else if (pp->hand[0] == C_INIT && Topcard > Deck)
246 goto mustpick;
247 pp->safety[card - S_CONV] = S_PLAYED;
248 pp->total += SC_SAFETY;
249 pp->hand_tot += SC_SAFETY;
250 if ((pp->safescore += SC_SAFETY) == NUM_SAFE * SC_SAFETY) {
251 pp->total += SC_ALL_SAFE;
252 pp->hand_tot += SC_ALL_SAFE;
253 }
254 if (card == C_RIGHT_WAY) {
255 if (pp->speed == C_LIMIT)
256 pp->speed = C_INIT;
257 if (pp->battle == C_STOP || pp->battle == C_INIT) {
258 pp->can_go = TRUE;
259 pp->battle = C_INIT;
260 }
261 if (!pp->can_go && isrepair(pp->battle))
262 pp->can_go = TRUE;
263 }
264 Next = -1;
265 break;
266
267 case C_INIT:
268 error("no card there");
269 Next = -1;
270 break;
271 }
272 if (pp == &Player[PLAYER])
273 account(card);
274 pp->hand[Card_no] = C_INIT;
275 Next = (Next == -1 ? FALSE : TRUE);
276 return TRUE;
277}
278
279getmove()
280{
281 reg char c, *sp;
282 static char moveprompt[] = ">>:Move:";
283#ifdef EXTRAP
284 static bool last_ex = FALSE; /* set if last command was E */
285
286 if (last_ex) {
287 undoex();
288 prboard();
289 last_ex = FALSE;
290 }
291#endif
292 for (;;) {
293 stand(MOVE_Y, MOVE_X, moveprompt);
294 clrtoeol();
295 move(MOVE_Y, MOVE_X + sizeof moveprompt);
296 leaveok(Board, FALSE);
297 refresh();
298 while ((c = getch()) == _tty.sg_kill || c == _tty.sg_erase)
299 continue;
300 if (islower(c))
301 c = toupper(c);
302 if (isprint(c) && !isspace(c)) {
303 addch(c);
304 refresh();
305 }
306 switch (c)
307 {
308 case 'P': /* Pick */
309 Movetype = M_DRAW;
310 goto ret;
311 case 'U': /* Use Card */
312 case 'D': /* Discard Card */
313 if ((Card_no = getcard()) < 0)
314 break;
315 Movetype = (c == 'U' ? M_PLAY : M_DISCARD);
316 goto ret;
317 case 'O': /* Order */
318 Order = !Order;
319 Movetype = M_ORDER;
320 goto ret;
321 case 'Q': /* Quit */
322 rub(); /* Same as a rubout */
323 break;
324 case 'W': /* Window toggle */
325 Window = nextwin(Window);
326 newscore();
327 prscore(TRUE);
328 wrefresh(Score);
329 break;
330 case 'R': /* Redraw screen */
e804469b 331 case CTRL(l):
8dd2ca95
C
332 clearok(curscr, TRUE);
333 newboard();
334 prboard();
335 break;
336 case 'S': /* Save game */
337 On_exit = FALSE;
338 save();
339 break;
340 case 'E': /* Extrapolate */
341#ifdef EXTRAP
342 if (last_ex)
343 break;
344 Finished = TRUE;
345 if (Window != W_FULL)
346 newscore();
347 prscore(FALSE);
348 wrefresh(Score);
349 last_ex = TRUE;
350 Finished = FALSE;
351#else
352 error("%c: command not implemented", c);
353#endif
354 break;
355 case '\r': /* Ignore RETURNs and */
356 case '\n': /* Line Feeds */
357 case ' ': /* and Spaces */
358 break;
359 case 'Z': /* Debug code */
360 if (geteuid() == ARNOLD) {
361 if (!Debug && outf == NULL) {
362 char buf[40];
363over:
364 mvaddstr(MOVE_Y, MOVE_X, "file: ");
365 clrtoeol();
366 leaveok(Board, FALSE);
367 refresh();
368 sp = buf;
369 while ((*sp = getch()) != '\n') {
370 if (*sp == _tty.sg_kill)
371 goto over;
372 else if (*sp == _tty.sg_erase) {
373 if (--sp < buf)
374 sp = buf;
375 else {
376 addch('\b');
377 if (*sp < ' ')
378 addch('\b');
379 clrtoeol();
380 }
381 }
382 else
383 addstr(unctrl(*sp++));
384 refresh();
385 }
386 *sp = '\0';
387 leaveok(Board, TRUE);
388 if ((outf = fopen(buf, "w")) == NULL)
389 perror(buf);
390 setbuf(outf, 0);
391 }
392 Debug = !Debug;
393 break;
394 }
395 /* FALLTHROUGH */
396 default:
397 error("unknown command: %s", unctrl(c));
398 break;
399 }
400 }
401ret:
402 leaveok(Board, TRUE);
403}
404/*
405 * return whether or not the player has picked
406 */
407haspicked(pp)
408reg PLAY *pp; {
409
410 reg int card;
411
412 if (Topcard <= Deck)
413 return TRUE;
414 switch (pp->hand[Card_no]) {
415 case C_GAS_SAFE: case C_SPARE_SAFE:
416 case C_DRIVE_SAFE: case C_RIGHT_WAY:
417 card = 1;
418 break;
419 default:
420 card = 0;
421 break;
422 }
423 return (pp->hand[card] != C_INIT);
424}
425
426account(card)
427reg CARD card; {
428
429 reg CARD oppos;
430
431 if (card == C_INIT)
432 return;
433 ++Numseen[card];
434 if (Play == COMP)
435 switch (card) {
436 case C_GAS_SAFE:
437 case C_SPARE_SAFE:
438 case C_DRIVE_SAFE:
439 oppos = opposite(card);
440 Numgos += Numcards[oppos] - Numseen[oppos];
441 break;
442 case C_CRASH:
443 case C_FLAT:
444 case C_EMPTY:
445 case C_STOP:
446 Numgos++;
447 break;
448 }
449}
450
451sort(hand)
452reg CARD *hand;
453{
454 reg CARD *cp, *tp;
455 reg int j;
456 reg CARD temp;
457
458 cp = hand;
459 hand += HAND_SZ;
460 for ( ; cp < &hand[-1]; cp++)
461 for (tp = cp + 1; tp < hand; tp++)
462 if (*cp > *tp) {
463 temp = *cp;
464 *cp = *tp;
465 *tp = temp;
466 }
467}