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