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