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