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