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