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