]> git.cameronkatri.com Git - bsdgames-darwin.git/blob - mille/move.c
don't try to switch a char and have a case of EOF - use an int.
[bsdgames-darwin.git] / mille / move.c
1 /* $NetBSD: move.c,v 1.15 2004/11/05 21:30:32 dsl 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. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
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 /* not lint */
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 * @(#)move.c 1.2 (Berkeley) 3/28/83
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 * move blank card to top by one of two methods. If the
144 * computer's hand was sorted, the randomness for picking
145 * between equally valued cards would be lost
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 * Check and see if either side can go. If they cannot,
168 * the game is over
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 * check and see if player has picked
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 * if not coup, must pick first
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; /* set if last command was E */
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': /* Pick */
378 Movetype = M_DRAW;
379 goto ret;
380 case 'U': /* Use Card */
381 case 'D': /* Discard Card */
382 if ((Card_no = getcard()) < 0)
383 break;
384 Movetype = (c == 'U' ? M_PLAY : M_DISCARD);
385 goto ret;
386 case 'O': /* Order */
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': /* Quit */
400 rub(0); /* Same as a rubout */
401 break;
402 case 'W': /* Window toggle */
403 Window = nextwin(Window);
404 newscore();
405 prscore(TRUE);
406 wrefresh(Score);
407 break;
408 case 'R': /* Redraw screen */
409 case CTRL('L'):
410 wrefresh(curscr);
411 break;
412 case 'S': /* Save game */
413 On_exit = FALSE;
414 save();
415 break;
416 case 'E': /* Extrapolate */
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': /* Ignore RETURNs and */
432 case '\n': /* Line Feeds */
433 case ' ': /* Spaces */
434 case '\0': /* and nulls */
435 break;
436 #ifdef DEBUG
437 case 'Z': /* Debug code */
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 * return whether or not the player has picked
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]);
555 if (promptno == MOVEPROMPT)
556 standend();
557 addch(' ');
558 last_prompt = promptno;
559 }
560 clrtoeol();
561 }
562
563 void
564 sort(hand)
565 CARD *hand;
566 {
567 CARD *cp, *tp;
568 CARD temp;
569
570 cp = hand;
571 hand += HAND_SZ;
572 for ( ; cp < &hand[-1]; cp++)
573 for (tp = cp + 1; tp < hand; tp++)
574 if (*cp > *tp) {
575 temp = *cp;
576 *cp = *tp;
577 *tp = temp;
578 }
579 }