]> git.cameronkatri.com Git - bsdgames-darwin.git/blob - mille/move.c
422e8db72df5d703f4fc352293a5a32f73a26e0e
[bsdgames-darwin.git] / mille / move.c
1 /* $NetBSD: move.c,v 1.4 1995/03/24 05:01:57 cgd 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 #ifndef lint
37 #if 0
38 static char sccsid[] = "@(#)move.c 8.1 (Berkeley) 5/31/93";
39 #else
40 static char rcsid[] = "$NetBSD: move.c,v 1.4 1995/03/24 05:01:57 cgd Exp $";
41 #endif
42 #endif /* not lint */
43
44 #include <termios.h>
45
46 #include "mille.h"
47 #ifndef unctrl
48 #include "unctrl.h"
49 #endif
50
51 # ifdef attron
52 # include <term.h>
53 # define _tty cur_term->Nttyb
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 domove()
68 {
69 reg PLAY *pp;
70 reg int i, j;
71 reg bool goodplay;
72
73 pp = &Player[Play];
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 (issafety(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 (issafety(*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 check_go() {
171
172 reg CARD card;
173 reg PLAY *pp, *op;
174 reg int i;
175
176 for (pp = Player; pp < &Player[2]; pp++) {
177 op = (pp == &Player[COMP] ? &Player[PLAYER] : &Player[COMP]);
178 for (i = 0; i < HAND_SZ; i++) {
179 card = pp->hand[i];
180 if (issafety(card) || canplay(pp, op, card)) {
181 #ifdef DEBUG
182 if (Debug) {
183 fprintf(outf, "CHECK_GO: can play %s (%d), ", C_name[card], card);
184 fprintf(outf, "issafety(card) = %d, ", issafety(card));
185 fprintf(outf, "canplay(pp, op, card) = %d\n", canplay(pp, op, card));
186 }
187 #endif
188 return;
189 }
190 #ifdef DEBUG
191 else if (Debug)
192 fprintf(outf, "CHECK_GO: cannot play %s\n",
193 C_name[card]);
194 #endif
195 }
196 }
197 Finished = TRUE;
198 }
199
200 playcard(pp)
201 reg PLAY *pp;
202 {
203 reg int v;
204 reg CARD card;
205
206 /*
207 * check and see if player has picked
208 */
209 switch (pp->hand[Card_no]) {
210 default:
211 if (!haspicked(pp))
212 mustpick:
213 return error("must pick first");
214 case C_GAS_SAFE: case C_SPARE_SAFE:
215 case C_DRIVE_SAFE: case C_RIGHT_WAY:
216 break;
217 }
218
219 card = pp->hand[Card_no];
220 #ifdef DEBUG
221 if (Debug)
222 fprintf(outf, "PLAYCARD: Card = %s\n", C_name[card]);
223 #endif
224 Next = FALSE;
225 switch (card) {
226 case C_200:
227 if (pp->nummiles[C_200] == 2)
228 return error("only two 200's per hand");
229 case C_100: case C_75:
230 if (pp->speed == C_LIMIT)
231 return error("limit of 50");
232 case C_50:
233 if (pp->mileage + Value[card] > End)
234 return error("puts you over %d", End);
235 case C_25:
236 if (!pp->can_go)
237 return error("cannot move now");
238 pp->nummiles[card]++;
239 v = Value[card];
240 pp->total += v;
241 pp->hand_tot += v;
242 if ((pp->mileage += v) == End)
243 check_ext(FALSE);
244 break;
245
246 case C_GAS: case C_SPARE: case C_REPAIRS:
247 if (pp->battle != opposite(card))
248 return error("can't play \"%s\"", C_name[card]);
249 pp->battle = card;
250 if (pp->safety[S_RIGHT_WAY] == S_PLAYED)
251 pp->can_go = TRUE;
252 break;
253
254 case C_GO:
255 if (pp->battle != C_INIT && pp->battle != C_STOP
256 && !isrepair(pp->battle))
257 return error("cannot play \"Go\" on a \"%s\"",
258 C_name[pp->battle]);
259 pp->battle = C_GO;
260 pp->can_go = TRUE;
261 break;
262
263 case C_END_LIMIT:
264 if (pp->speed != C_LIMIT)
265 return error("not limited");
266 pp->speed = C_END_LIMIT;
267 break;
268
269 case C_EMPTY: case C_FLAT: case C_CRASH:
270 case C_STOP:
271 pp = &Player[other(Play)];
272 if (!pp->can_go)
273 return error("opponent cannot go");
274 else if (pp->safety[safety(card) - S_CONV] == S_PLAYED)
275 protected:
276 return error("opponent is protected");
277 pp->battle = card;
278 pp->new_battle = TRUE;
279 pp->can_go = FALSE;
280 pp = &Player[Play];
281 break;
282
283 case C_LIMIT:
284 pp = &Player[other(Play)];
285 if (pp->speed == C_LIMIT)
286 return error("opponent has limit");
287 if (pp->safety[S_RIGHT_WAY] == S_PLAYED)
288 goto protected;
289 pp->speed = C_LIMIT;
290 pp->new_speed = TRUE;
291 pp = &Player[Play];
292 break;
293
294 case C_GAS_SAFE: case C_SPARE_SAFE:
295 case C_DRIVE_SAFE: case C_RIGHT_WAY:
296 if (pp->battle == opposite(card)
297 || (card == C_RIGHT_WAY && pp->speed == C_LIMIT)) {
298 if (!(card == C_RIGHT_WAY && !isrepair(pp->battle))) {
299 pp->battle = C_GO;
300 pp->can_go = TRUE;
301 }
302 if (card == C_RIGHT_WAY && pp->speed == C_LIMIT)
303 pp->speed = C_INIT;
304 if (pp->new_battle
305 || (pp->new_speed && card == C_RIGHT_WAY)) {
306 pp->coups[card - S_CONV] = TRUE;
307 pp->total += SC_COUP;
308 pp->hand_tot += SC_COUP;
309 pp->coupscore += SC_COUP;
310 }
311 }
312 /*
313 * if not coup, must pick first
314 */
315 else if (pp->hand[0] == C_INIT && Topcard > Deck)
316 goto mustpick;
317 pp->safety[card - S_CONV] = S_PLAYED;
318 pp->total += SC_SAFETY;
319 pp->hand_tot += SC_SAFETY;
320 if ((pp->safescore += SC_SAFETY) == NUM_SAFE * SC_SAFETY) {
321 pp->total += SC_ALL_SAFE;
322 pp->hand_tot += SC_ALL_SAFE;
323 }
324 if (card == C_RIGHT_WAY) {
325 if (pp->speed == C_LIMIT)
326 pp->speed = C_INIT;
327 if (pp->battle == C_STOP || pp->battle == C_INIT) {
328 pp->can_go = TRUE;
329 pp->battle = C_INIT;
330 }
331 if (!pp->can_go && isrepair(pp->battle))
332 pp->can_go = TRUE;
333 }
334 Next = -1;
335 break;
336
337 case C_INIT:
338 error("no card there");
339 Next = -1;
340 break;
341 }
342 if (pp == &Player[PLAYER])
343 account(card);
344 pp->hand[Card_no] = C_INIT;
345 Next = (Next == -1 ? FALSE : TRUE);
346 return TRUE;
347 }
348
349 getmove()
350 {
351 reg char c, *sp;
352 #ifdef EXTRAP
353 static bool last_ex = FALSE; /* set if last command was E */
354
355 if (last_ex) {
356 undoex();
357 prboard();
358 last_ex = FALSE;
359 }
360 #endif
361 for (;;) {
362 prompt(MOVEPROMPT);
363 leaveok(Board, FALSE);
364 refresh();
365 while ((c = readch()) == killchar() || c == erasechar())
366 continue;
367 if (islower(c))
368 c = toupper(c);
369 if (isprint(c) && !isspace(c)) {
370 addch(c);
371 refresh();
372 }
373 switch (c) {
374 case 'P': /* Pick */
375 Movetype = M_DRAW;
376 goto ret;
377 case 'U': /* Use Card */
378 case 'D': /* Discard Card */
379 if ((Card_no = getcard()) < 0)
380 break;
381 Movetype = (c == 'U' ? M_PLAY : M_DISCARD);
382 goto ret;
383 case 'O': /* Order */
384 Order = !Order;
385 if (Window == W_SMALL) {
386 if (!Order)
387 mvwaddstr(Score, 12, 21,
388 "o: order hand");
389 else
390 mvwaddstr(Score, 12, 21,
391 "o: stop ordering");
392 wclrtoeol(Score);
393 }
394 Movetype = M_ORDER;
395 goto ret;
396 case 'Q': /* Quit */
397 rub(); /* Same as a rubout */
398 break;
399 case 'W': /* Window toggle */
400 Window = nextwin(Window);
401 newscore();
402 prscore(TRUE);
403 wrefresh(Score);
404 break;
405 case 'R': /* Redraw screen */
406 case CTRL('L'):
407 wrefresh(curscr);
408 break;
409 case 'S': /* Save game */
410 On_exit = FALSE;
411 save();
412 break;
413 case 'E': /* Extrapolate */
414 #ifdef EXTRAP
415 if (last_ex)
416 break;
417 Finished = TRUE;
418 if (Window != W_FULL)
419 newscore();
420 prscore(FALSE);
421 wrefresh(Score);
422 last_ex = TRUE;
423 Finished = FALSE;
424 #else
425 error("%c: command not implemented", c);
426 #endif
427 break;
428 case '\r': /* Ignore RETURNs and */
429 case '\n': /* Line Feeds */
430 case ' ': /* Spaces */
431 case '\0': /* and nulls */
432 break;
433 #ifdef DEBUG
434 case 'Z': /* Debug code */
435 if (!Debug && outf == NULL) {
436 char buf[MAXPATHLEN];
437
438 prompt(FILEPROMPT);
439 leaveok(Board, FALSE);
440 refresh();
441 sp = buf;
442 while ((*sp = readch()) != '\n') {
443 if (*sp == killchar())
444 goto over;
445 else if (*sp == erasechar()) {
446 if (--sp < buf)
447 sp = buf;
448 else {
449 addch('\b');
450 if (*sp < ' ')
451 addch('\b');
452 clrtoeol();
453 }
454 }
455 else
456 addstr(unctrl(*sp++));
457 refresh();
458 }
459 *sp = '\0';
460 leaveok(Board, TRUE);
461 if ((outf = fopen(buf, "w")) == NULL)
462 perror(buf);
463 setbuf(outf, (char *)NULL);
464 }
465 Debug = !Debug;
466 break;
467 #endif
468 default:
469 error("unknown command: %s", unctrl(c));
470 break;
471 }
472 }
473 ret:
474 leaveok(Board, TRUE);
475 }
476 /*
477 * return whether or not the player has picked
478 */
479 haspicked(pp)
480 reg PLAY *pp; {
481
482 reg int card;
483
484 if (Topcard <= Deck)
485 return TRUE;
486 switch (pp->hand[Card_no]) {
487 case C_GAS_SAFE: case C_SPARE_SAFE:
488 case C_DRIVE_SAFE: case C_RIGHT_WAY:
489 card = 1;
490 break;
491 default:
492 card = 0;
493 break;
494 }
495 return (pp->hand[card] != C_INIT);
496 }
497
498 account(card)
499 reg CARD card; {
500
501 reg CARD oppos;
502
503 if (card == C_INIT)
504 return;
505 ++Numseen[card];
506 if (Play == COMP)
507 switch (card) {
508 case C_GAS_SAFE:
509 case C_SPARE_SAFE:
510 case C_DRIVE_SAFE:
511 oppos = opposite(card);
512 Numgos += Numcards[oppos] - Numseen[oppos];
513 break;
514 case C_CRASH:
515 case C_FLAT:
516 case C_EMPTY:
517 case C_STOP:
518 Numgos++;
519 break;
520 }
521 }
522
523 prompt(promptno)
524 int promptno;
525 {
526 static char *names[] = {
527 ">>:Move:",
528 "Really?",
529 "Another hand?",
530 "Another game?",
531 "Save game?",
532 "Same file?",
533 "file:",
534 "Extension?",
535 "Overwrite file?",
536 };
537 static int last_prompt = -1;
538
539 if (promptno == last_prompt)
540 move(MOVE_Y, MOVE_X + strlen(names[promptno]) + 1);
541 else {
542 move(MOVE_Y, MOVE_X);
543 if (promptno == MOVEPROMPT)
544 standout();
545 addstr(names[promptno]);
546 if (promptno == MOVEPROMPT)
547 standend();
548 addch(' ');
549 last_prompt = promptno;
550 }
551 clrtoeol();
552 }
553
554 sort(hand)
555 reg CARD *hand;
556 {
557 reg CARD *cp, *tp;
558 reg CARD temp;
559
560 cp = hand;
561 hand += HAND_SZ;
562 for ( ; cp < &hand[-1]; cp++)
563 for (tp = cp + 1; tp < hand; tp++)
564 if (*cp > *tp) {
565 temp = *cp;
566 *cp = *tp;
567 *tp = temp;
568 }
569 }
570