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