xref: /netbsd/games/backgammon/backgammon/main.c (revision bf9ec67e)
1 /*	$NetBSD: main.c,v 1.17 2001/09/18 18:15:49 wiz Exp $	*/
2 
3 /*
4  * Copyright (c) 1980, 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 __COPYRIGHT("@(#) Copyright (c) 1980, 1993\n\
39 	The Regents of the University of California.  All rights reserved.\n");
40 #endif /* not lint */
41 
42 #ifndef lint
43 #if 0
44 static char sccsid[] = "@(#)main.c	8.1 (Berkeley) 5/31/93";
45 #else
46 __RCSID("$NetBSD: main.c,v 1.17 2001/09/18 18:15:49 wiz Exp $");
47 #endif
48 #endif				/* not lint */
49 
50 #include <time.h>
51 
52 #include "back.h"
53 #include "backlocal.h"
54 
55 #define MVPAUSE	5		/* time to sleep when stuck */
56 
57 extern const char   *const instr[];		/* text of instructions */
58 extern const char   *const message[];		/* update message */
59 short ospeed;			/* tty output speed */
60 
61 const char   *const helpm[] = {		/* help message */
62 	"Enter a space or newline to roll, or",
63 	"     R   to reprint the board\tD   to double",
64 	"     S   to save the game\tQ   to quit",
65 	0
66 };
67 
68 const char   *const contin[] = {		/* pause message */
69 	"(Type a newline to continue.)",
70 	"",
71 	0
72 };
73 static const char rules[] = "\nDo you want the rules of the game?";
74 static const char noteach[] = "Teachgammon not available!\n\a";
75 static const char need[] = "Do you need instructions for this program?";
76 static const char askcol[] =
77 "Enter 'r' to play red, 'w' to play white, 'b' to play both:";
78 static const char rollr[] = "Red rolls a ";
79 static const char rollw[] = ".  White rolls a ";
80 static const char rstart[] = ".  Red starts.\n";
81 static const char wstart[] = ".  White starts.\n";
82 static const char toobad1[] = "Too bad, ";
83 static const char unable[] = " is unable to use that roll.\n";
84 static const char toobad2[] = ".  Too bad, ";
85 static const char cantmv[] = " can't move.\n";
86 static const char bgammon[] = "Backgammon!  ";
87 static const char gammon[] = "Gammon!  ";
88 static const char again[] = ".\nWould you like to play again?";
89 static const char svpromt[] = "Would you like to save this game?";
90 
91 static const char password[] = "losfurng";
92 static char pbuf[10];
93 
94 int
95 main(argc, argv)
96 	int     argc;
97 	char  **argv;
98 {
99 	int     i;		/* non-descript index */
100 	int     l;		/* non-descript index */
101 	char    c;		/* non-descript character storage */
102 	long    t;		/* time for random num generator */
103 
104 	/* revoke setgid privileges */
105 	setgid(getgid());
106 
107 	/* initialization */
108 	bflag = 2;		/* default no board */
109 	signal(SIGINT, getout);	/* trap interrupts */
110 	if (tcgetattr(0, &old) == -1)	/* get old tty mode */
111 		errexit("backgammon(gtty)");
112 	noech = old;
113 	noech.c_lflag &= ~ECHO;
114 	raw = noech;
115 	raw.c_lflag &= ~ICANON;	/* set up modes */
116 	ospeed = cfgetospeed(&old);	/* for termlib */
117 
118 	/* get terminal capabilities, and decide if it can cursor address */
119 	tflag = getcaps(getenv("TERM"));
120 	/* use whole screen for text */
121 	if (tflag)
122 		begscr = 0;
123 	t = time(NULL);
124 	srandom(t);		/* 'random' seed */
125 
126 #ifdef V7
127 	while (*++argv != 0)	/* process arguments */
128 #else
129 	while (*++argv != -1)	/* process arguments */
130 #endif
131 		getarg(&argv);
132 	args[acnt] = '\0';
133 	if (tflag) {		/* clear screen */
134 		noech.c_oflag &= ~(ONLCR | OXTABS);
135 		raw.c_oflag &= ~(ONLCR | OXTABS);
136 		clear();
137 	}
138 	fixtty(&raw);		/* go into raw mode */
139 
140 	/* check if restored game and save flag for later */
141 	if ((rfl = rflag) != 0) {
142 		text(message);	/* print message */
143 		text(contin);
144 		wrboard();	/* print board */
145 		/* if new game, pretend to be a non-restored game */
146 		if (cturn == 0)
147 			rflag = 0;
148 	} else {
149 		rscore = wscore = 0;	/* zero score */
150 		text(message);	/* update message without pausing */
151 
152 		if (aflag) {	/* print rules */
153 			writel(rules);
154 			if (yorn(0)) {
155 
156 				fixtty(&old);	/* restore tty */
157 				execl(TEACH, "teachgammon", args[0]?args:0, 0);
158 
159 				tflag = 0;	/* error! */
160 				writel(noteach);
161 				exit(1);
162 			} else {/* if not rules, then instructions */
163 				writel(need);
164 				if (yorn(0)) {	/* print instructions */
165 					clear();
166 					text(instr);
167 				}
168 			}
169 		}
170 		init();		/* initialize board */
171 
172 		if (pnum == 2) {/* ask for color(s) */
173 			writec('\n');
174 			writel(askcol);
175 			while (pnum == 2) {
176 				c = readc();
177 				switch (c) {
178 
179 				case 'R':	/* red */
180 					pnum = -1;
181 					break;
182 
183 				case 'W':	/* white */
184 					pnum = 1;
185 					break;
186 
187 				case 'B':	/* both */
188 					pnum = 0;
189 					break;
190 
191 				case 'P':
192 					if (iroll)
193 						break;
194 					if (tflag)
195 						curmove(curr, 0);
196 					else
197 						writec('\n');
198 					writel("Password:");
199 					signal(SIGALRM, getout);
200 					cflag = 1;
201 					alarm(10);
202 					for (i = 0; i < 10; i++) {
203 						pbuf[i] = readc();
204 						if (pbuf[i] == '\n')
205 							break;
206 					}
207 					if (i == 10)
208 						while (readc() != '\n');
209 					alarm(0);
210 					cflag = 0;
211 					if (i < 10)
212 						pbuf[i] = '\0';
213 					for (i = 0; i < 9; i++)
214 						if (pbuf[i] != password[i])
215 							getout(0);
216 					iroll = 1;
217 					if (tflag)
218 						curmove(curr, 0);
219 					else
220 						writec('\n');
221 					writel(askcol);
222 					break;
223 
224 				default:	/* error */
225 					writec('\007');
226 				}
227 			}
228 		} else
229 			if (!aflag)
230 				/* pause to read message */
231 				text(contin);
232 
233 		wrboard();	/* print board */
234 
235 		if (tflag)
236 			curmove(18, 0);
237 		else
238 			writec('\n');
239 	}
240 	/* limit text to bottom of screen */
241 	if (tflag)
242 		begscr = 17;
243 
244 	for (;;) {		/* begin game! */
245 		/* initial roll if needed */
246 		if ((!rflag) || raflag)
247 			roll();
248 
249 		/* perform ritual of first roll */
250 		if (!rflag) {
251 			if (tflag)
252 				curmove(17, 0);
253 			while (D0 == D1)	/* no doubles */
254 				roll();
255 
256 			/* print rolls */
257 			writel(rollr);
258 			writec(D0 + '0');
259 			writel(rollw);
260 			writec(D1 + '0');
261 
262 			/* winner goes first */
263 			if (D0 > D1) {
264 				writel(rstart);
265 				cturn = 1;
266 			} else {
267 				writel(wstart);
268 				cturn = -1;
269 			}
270 		}
271 		/* initialize variables according to whose turn it is */
272 
273 		if (cturn == 1) {	/* red */
274 			home = 25;
275 			bar = 0;
276 			inptr = &in[1];
277 			inopp = &in[0];
278 			offptr = &off[1];
279 			offopp = &off[0];
280 			Colorptr = &color[1];
281 			colorptr = &color[3];
282 			colen = 3;
283 		} else {	/* white */
284 			home = 0;
285 			bar = 25;
286 			inptr = &in[0];
287 			inopp = &in[1];
288 			offptr = &off[0];
289 			offopp = &off[1];
290 			Colorptr = &color[0];
291 			colorptr = &color[2];
292 			colen = 5;
293 		}
294 
295 		/* do first move (special case) */
296 		if (!(rflag && raflag)) {
297 			if (cturn == pnum)	/* computer's move */
298 				move(0);
299 			else {	/* player's move */
300 				mvlim = movallow();
301 				/* reprint roll */
302 				if (tflag)
303 					curmove(cturn == -1 ? 18 : 19, 0);
304 				proll();
305 				getmove();	/* get player's move */
306 			}
307 		}
308 		if (tflag) {
309 			curmove(17, 0);
310 			cline();
311 			begscr = 18;
312 		}
313 		/* no longer any diff- erence between normal game and
314 		 * recovered game. */
315 		rflag = 0;
316 
317 		/* move as long as it's someone's turn */
318 		while (cturn == 1 || cturn == -1) {
319 
320 			/* board maintainence */
321 			if (tflag)
322 				refresh();	/* fix board */
323 			else
324 				/* redo board if -p */
325 				if (cturn == bflag || bflag == 0)
326 					wrboard();
327 
328 			/* do computer's move */
329 			if (cturn == pnum) {
330 				move(1);
331 
332 				/* see if double refused */
333 				if (cturn == -2 || cturn == 2)
334 					break;
335 
336 				/* check for winning move */
337 				if (*offopp == 15) {
338 					cturn *= -2;
339 					break;
340 				}
341 				continue;
342 
343 			}
344 			/* (player's move) */
345 
346 			/* clean screen if safe */
347 			if (tflag && hflag) {
348 				curmove(20, 0);
349 				clend();
350 				hflag = 1;
351 			}
352 			/* if allowed, give him a chance to double */
353 			if (dlast != cturn && gvalue < 64) {
354 				if (tflag)
355 					curmove(cturn == -1 ? 18 : 19, 0);
356 				writel(*Colorptr);
357 				c = readc();
358 
359 				/* character cases */
360 				switch (c) {
361 
362 					/* reprint board */
363 				case 'R':
364 					wrboard();
365 					break;
366 
367 					/* save game */
368 				case 'S':
369 					raflag = 1;
370 					save(1);
371 					break;
372 
373 					/* quit */
374 				case 'Q':
375 					quit();
376 					break;
377 
378 					/* double */
379 				case 'D':
380 					dble();
381 					break;
382 
383 					/* roll */
384 				case ' ':
385 				case '\n':
386 					roll();
387 					writel(" rolls ");
388 					writec(D0 + '0');
389 					writec(' ');
390 					writec(D1 + '0');
391 					writel(".  ");
392 
393 					/* see if he can move */
394 					if ((mvlim = movallow()) == 0) {
395 
396 						/* can't move */
397 						writel(toobad1);
398 						writel(*colorptr);
399 						writel(unable);
400 						if (tflag) {
401 							if (pnum) {
402 								buflush();
403 								sleep(MVPAUSE);
404 							}
405 						}
406 						nexturn();
407 						break;
408 					}
409 					/* get move */
410 					getmove();
411 
412 					/* okay to clean screen */
413 					hflag = 1;
414 					break;
415 
416 					/* invalid character */
417 				default:
418 
419 					/* print help message */
420 					if (tflag)
421 						curmove(20, 0);
422 					else
423 						writec('\n');
424 					text(helpm);
425 					if (tflag)
426 						curmove(cturn == -1 ? 18 : 19, 0);
427 					else
428 						writec('\n');
429 
430 					/* don't erase */
431 					hflag = 0;
432 				}
433 			} else {/* couldn't double */
434 
435 				/* print roll */
436 				roll();
437 				if (tflag)
438 					curmove(cturn == -1 ? 18 : 19, 0);
439 				proll();
440 
441 				/* can he move? */
442 				if ((mvlim = movallow()) == 0) {
443 
444 					/* he can't */
445 					writel(toobad2);
446 					writel(*colorptr);
447 					writel(cantmv);
448 					buflush();
449 					sleep(MVPAUSE);
450 					nexturn();
451 					continue;
452 				}
453 				/* get move */
454 				getmove();
455 			}
456 		}
457 
458 		/* don't worry about who won if quit */
459 		if (cturn == 0)
460 			break;
461 
462 		/* fix cturn = winner */
463 		cturn /= -2;
464 
465 		/* final board pos. */
466 		if (tflag)
467 			refresh();
468 
469 		/* backgammon? */
470 		mflag = 0;
471 		l = bar + 7 * cturn;
472 		for (i = bar; i != l; i += cturn)
473 			if (board[i] * cturn)
474 				mflag++;
475 
476 		/* compute game value */
477 		if (tflag)
478 			curmove(20, 0);
479 		if (*offopp == 15 && *offptr <= 0) {
480 			if (mflag) {
481 				writel(bgammon);
482 				gvalue *= 3;
483 			} else {
484 				writel(gammon);
485 				gvalue *= 2;
486 			}
487 		}
488 		/* report situation */
489 		if (cturn == -1) {
490 			writel("Red wins ");
491 			rscore += gvalue;
492 		} else {
493 			writel("White wins ");
494 			wscore += gvalue;
495 		}
496 		wrint(gvalue);
497 		writel(" point");
498 		if (gvalue > 1)
499 			writec('s');
500 		writel(".\n");
501 
502 		/* write score */
503 		wrscore();
504 
505 		/* see if he wants another game */
506 		writel(again);
507 		if ((i = yorn('S')) == 0)
508 			break;
509 
510 		init();
511 		if (i == 2) {
512 			writel("  Save.\n");
513 			cturn = 0;
514 			save(0);
515 		}
516 		/* yes, reset game */
517 		wrboard();
518 	}
519 
520 	/* give him a chance to save if game was recovered */
521 	if (rfl && cturn) {
522 		writel(svpromt);
523 		if (yorn(0)) {
524 			/* re-initialize for recovery */
525 			init();
526 			cturn = 0;
527 			save(0);
528 		}
529 	}
530 	/* leave peacefully */
531 	getout(0);
532 	/* NOTREACHED */
533 	return (0);
534 }
535