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