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