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