1 /*
2  * Copyright (c) 1980, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This product includes software developed by the University of
16  *	California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * @(#) Copyright (c) 1980, 1993 The Regents of the University of California.  All rights reserved.
34  * @(#)main.c	8.1 (Berkeley) 5/31/93
35  * $FreeBSD: src/games/backgammon/backgammon/main.c,v 1.13 1999/11/30 03:48:22 billf Exp $
36  * $DragonFly: src/games/backgammon/backgammon/main.c,v 1.3 2006/08/08 16:36:11 pavalos Exp $
37  */
38 
39 #include <stdio.h>
40 #include <string.h>
41 #include <signal.h>
42 #include "back.h"
43 
44 #define MVPAUSE	5				/* time to sleep when stuck */
45 #define MAXUSERS 35				/* maximum number of users */
46 
47 extern const char	*const instr[];		/* text of instructions */
48 extern const char	*const message[];	/* update message */
49 
50 const char	*helpm[] = {			/* help message */
51 	"Enter a space or newline to roll, or",
52 	"     R   to reprint the board\tD   to double",
53 	"     S   to save the game\tQ   to quit",
54 	0
55 };
56 
57 const char	*contin[] = {			/* pause message */
58 	"(Type a newline to continue.)",
59 	"",
60 	0
61 };
62 
63 static const char	rules[] = "\nDo you want the rules of the game?";
64 static const char	noteach[] = "Teachgammon not available!\n\007";
65 static const char	need[] = "Do you need instructions for this program?";
66 static const char	askcol[] =
67 	"Enter 'r' to play red, 'w' to play white, 'b' to play both:";
68 static const char	rollr[] = "Red rolls a ";
69 static const char	rollw[] = ".  White rolls a ";
70 static const char	rstart[] = ".  Red starts.\n";
71 static const char	wstart[] = ".  White starts.\n";
72 static const char	toobad1[] = "Too bad, ";
73 static const char	unable[] = " is unable to use that roll.\n";
74 static const char	toobad2[] = ".  Too bad, ";
75 static const char	cantmv[] = " can't move.\n";
76 static const char	bgammon[] = "Backgammon!  ";
77 static const char	gammon[] = "Gammon!  ";
78 static const char	again[] = ".\nWould you like to play again?";
79 static const char	svpromt[] = "Would you like to save this game?";
80 
81 static const char	password[] = "losfurng";
82 static char	pbuf[10];
83 
84 int
85 main(int argc, char **argv)
86 {
87 	int	i;		/* non-descript index */
88 	int	l;		/* non-descript index */
89 	char	c;		/* non-descript character storage */
90 
91 	/* revoke privs */
92 	setgid(getgid());
93 
94 	/* initialization */
95 	bflag = 2;					/* default no board */
96 	acnt = 1;                                       /* Nuber of args */
97 	signal (SIGINT,(sig_t)getout);			/* trap interrupts */
98 	if (ioctl(0, TIOCGETP, &tty) == -1)		/* get old tty mode */
99 		errexit ("backgammon(gtty)");
100 	old = tty.sg_flags;
101 #ifdef V7
102 	raw = ((noech = old & ~ECHO) | CBREAK);		/* set up modes */
103 #else
104 	raw = ((noech = old & ~ECHO) | RAW);		/* set up modes */
105 #endif
106 
107 							/* get terminal
108 							 * capabilities, and
109 					   		 * decide if it can
110 							 * cursor address */
111 	tflag = getcaps (getenv ("TERM"));
112 							/* use whole screen
113 							 * for text */
114 	if (tflag)
115 		begscr = 0;
116 	srandomdev();
117 
118 	getarg (argc, argv);
119 	args[acnt] = NULL;
120 	if (tflag)  {					/* clear screen */
121 		noech &= ~(CRMOD|XTABS);
122 		raw &= ~(CRMOD|XTABS);
123 		clear();
124 	}
125 	fixtty (raw);					/* go into raw mode */
126 
127 							/* check if restored
128 							 * game and save flag
129 							 * for later */
130 	if ((rfl = rflag) != 0)  {
131 		text (message);				/* print message */
132 		text (contin);
133 		wrboard();				/* print board */
134 							/* if new game, pretend
135 							 * to be a non-restored
136 							 * game */
137 		if (cturn == 0)
138 			rflag = 0;
139 	} else  {
140 		rscore = wscore = 0;			/* zero score */
141 		text (message);				/* update message
142 							 * without pausing */
143 
144 		if (aflag)  {				/* print rules */
145 			writel (rules);
146 			if (yorn(0))  {
147 
148 				fixtty (old);		/* restore tty */
149 				args[0] = strdup ("teachgammon");
150 				execv (TEACH,args);
151 
152 				tflag = 0;		/* error! */
153 				writel (noteach);
154 				exit(1);
155 			} else  {			/* if not rules, then
156 							 * instructions */
157 				writel (need);
158 				if (yorn(0))  {		/* print instructions */
159 					clear();
160 					text (instr);
161 				}
162 			}
163 		}
164 
165 		for (i = 0; i < acnt; i++)
166 			free (args[i]);
167 
168 		init();					/* initialize board */
169 
170 		if (pnum == 2)  {			/* ask for color(s) */
171 			writec ('\n');
172 			writel (askcol);
173 			while (pnum == 2)  {
174 				c = readc();
175 				switch (c)  {
176 
177 				case 'R':		/* red */
178 					pnum = -1;
179 					break;
180 
181 				case 'W':		/* white */
182 					pnum = 1;
183 					break;
184 
185 				case 'B':		/* both */
186 					pnum = 0;
187 					break;
188 
189 				case 'P':
190 					if (iroll)
191 						break;
192 					if (tflag)
193 						curmove (curr,0);
194 					else
195 						writec ('\n');
196 					writel ("Password:");
197 					signal (SIGALRM,(sig_t)getout);
198 					cflag = 1;
199 					alarm (10);
200 					for (i = 0; i < 10; i++)  {
201 						pbuf[i] = readc();
202 						if (pbuf[i] == '\n')
203 							break;
204 					}
205 					if (i == 10)
206 						while (readc() != '\n');
207 					alarm (0);
208 					cflag = 0;
209 					if (i < 10)
210 						pbuf[i] = '\0';
211 					for (i = 0; i < 9; i++)
212 						if (pbuf[i] != password[i])
213 							getout();
214 					iroll = 1;
215 					if (tflag)
216 						curmove (curr,0);
217 					else
218 						writec ('\n');
219 					writel (askcol);
220 					break;
221 
222 				default:		/* error */
223 					writec ('\007');
224 				}
225 			}
226 		} else  if (!aflag)
227 							/* pause to read
228 							 * message */
229 			text (contin);
230 
231 		wrboard();				/* print board */
232 
233 		if (tflag)
234 			curmove (18,0);
235 		else
236 			writec ('\n');
237 	}
238 							/* limit text to bottom
239 							 * of screen */
240 	if (tflag)
241 		begscr = 17;
242 
243 	for (;;)  {					/* begin game! */
244 							/* initial roll if
245 							 * needed */
246 		if ((! rflag) || raflag)
247 			roll();
248 
249 							/* perform ritual of
250 							 * first roll */
251 		if (! rflag)  {
252 			if (tflag)
253 				curmove (17,0);
254 			while (D0 == D1)		/* no doubles */
255 				roll();
256 
257 							/* print rolls */
258 			writel (rollr);
259 			writec (D0+'0');
260 			writel (rollw);
261 			writec (D1+'0');
262 
263 							/* winner goes first */
264 			if (D0 > D1)  {
265 				writel (rstart);
266 				cturn = 1;
267 			} else  {
268 				writel (wstart);
269 				cturn = -1;
270 			}
271 		}
272 
273 							/* initalize variables
274 							 * according to whose
275 							 * turn it is */
276 
277 		if (cturn == 1)  {			    /* red */
278 			home = 25;
279 			bar = 0;
280 			inptr = &in[1];
281 			inopp = &in[0];
282 			offptr = &off[1];
283 			offopp = &off[0];
284 			Colorptr = &color[1];
285 			colorptr = &color[3];
286 			colen = 3;
287 		} else  {				    /* white */
288 			home = 0;
289 			bar = 25;
290 			inptr = &in[0];
291 			inopp = &in[1];
292 			offptr = &off[0];
293 			offopp = &off[1];
294 			Colorptr = &color[0];
295 			colorptr = &color[2];
296 			colen = 5;
297 		}
298 
299 							/* do first move
300 							 * (special case) */
301 		if (! (rflag && raflag))  {
302 			if (cturn == pnum)		/* computer's move */
303 				move (0);
304 			else  {				/* player's move */
305 				mvlim = movallow();
306 							/* reprint roll */
307 				if (tflag)
308 					curmove (cturn == -1? 18: 19,0);
309 				proll();
310 				getmove();		/* get player's move */
311 			}
312 		}
313 		if (tflag)  {
314 			curmove (17,0);
315 			cline();
316 			begscr = 18;
317 		}
318 
319 							/* no longer any diff-
320 							 * erence between normal
321 							 * game and recovered
322 							 * game. */
323 		rflag = 0;
324 
325 							/* move as long as it's
326 							 * someone's turn */
327 		while (cturn == 1 || cturn == -1)  {
328 
329 							/* board maintainence */
330 			if (tflag)
331 				refresh();		/* fix board */
332 			else
333 							/* redo board if -p */
334 				if (cturn == bflag || bflag == 0)
335 					wrboard();
336 
337 							/* do computer's move */
338 			if (cturn == pnum)  {
339 				move (1);
340 
341 							/* see if double
342 							 * refused */
343 				if (cturn == -2 || cturn == 2)
344 					break;
345 
346 							/* check for winning
347 							 * move */
348 				if (*offopp == 15)  {
349 					cturn *= -2;
350 					break;
351 				}
352 				continue;
353 
354 			}
355 
356 							/* (player's move) */
357 
358 							/* clean screen if
359 							 * safe */
360 			if (tflag && hflag)  {
361 				curmove (20,0);
362 				clend ();
363 				hflag = 1;
364 			}
365 
366 							/* if allowed, give him
367 							 * a chance to double */
368 			if (dlast != cturn && gvalue < 64)  {
369 				if (tflag)
370 					curmove (cturn == -1? 18: 19,0);
371 				writel (*Colorptr);
372 				c = readc();
373 
374 							/* character cases */
375 				switch (c)  {
376 
377 							/* reprint board */
378 				case 'R':
379 					wrboard();
380 					break;
381 
382 							/* save game */
383 				case 'S':
384 					raflag = 1;
385 					save (1);
386 					break;
387 
388 							/* quit */
389 				case 'Q':
390 					quit();
391 					break;
392 
393 							/* double */
394 				case 'D':
395 					dble();
396 					break;
397 
398 							/* roll */
399 				case ' ':
400 				case '\n':
401 					roll();
402 					writel (" rolls ");
403 					writec (D0+'0');
404 					writec (' ');
405 					writec (D1+'0');
406 					writel (".  ");
407 
408 							/* see if he can move */
409 					if ( (mvlim = movallow()) == 0)  {
410 
411 							/* can't move */
412 						writel (toobad1);
413 						writel (*colorptr);
414 						writel (unable);
415 						if (tflag)  {
416 							if (pnum)  {
417 								buflush();
418 								sleep (MVPAUSE);
419 							}
420 						}
421 						nexturn();
422 						break;
423 					}
424 
425 							/* get move */
426 					getmove();
427 
428 							/* okay to clean
429 							 * screen */
430 					hflag = 1;
431 					break;
432 
433 							/* invalid character */
434 				default:
435 
436 							/* print help message */
437 					if (tflag)
438 						curmove (20,0);
439 					else
440 						writec ('\n');
441 					text (helpm);
442 					if (tflag)
443 						curmove (cturn == -1? 18: 19,0);
444 					else
445 						writec ('\n');
446 
447 							/* don't erase */
448 					hflag = 0;
449 				}
450 			} else  {			/* couldn't double */
451 
452 							/* print roll */
453 				roll();
454 				if (tflag)
455 					curmove (cturn == -1? 18: 19,0);
456 				proll ();
457 
458 							/* can he move? */
459 				if ((mvlim = movallow()) == 0)  {
460 
461 							/* he can't */
462 					writel (toobad2);
463 					writel (*colorptr);
464 					writel (cantmv);
465 					buflush();
466 					sleep (MVPAUSE);
467 					nexturn();
468 					continue;
469 				}
470 
471 							/* get move */
472 				getmove();
473 			}
474 		}
475 
476 							/* don't worry about who
477 							 * won if quit */
478 		if (cturn == 0)
479 			break;
480 
481 							/* fix cturn = winner */
482 		cturn /= -2;
483 
484 							/* final board pos. */
485 		if (tflag)
486 			refresh();
487 
488 							/* backgammon? */
489 		mflag = 0;
490 		l = bar+7*cturn;
491 		for (i = bar; i != l; i += cturn)
492 			if (board[i]*cturn)  mflag++;
493 
494 							/* compute game value */
495 		if (tflag)
496 			curmove (20,0);
497 		if (*offopp == 15)  {
498 			if (mflag)  {
499 				writel (bgammon);
500 				gvalue *= 3;
501 			}
502 			else  if (*offptr <= 0)  {
503 				writel (gammon);
504 				gvalue *= 2;
505 			}
506 		}
507 
508 							/* report situation */
509 		if (cturn == -1)  {
510 			writel ("Red wins ");
511 			rscore += gvalue;
512 		} else {
513 			writel ("White wins ");
514 			wscore += gvalue;
515 		}
516 		wrint (gvalue);
517 		writel (" point");
518 		if (gvalue > 1)
519 			writec ('s');
520 		writel (".\n");
521 
522 							/* write score */
523 		wrscore();
524 
525 							/* see if he wants
526 							 * another game */
527 		writel (again);
528 		if ((i = yorn ('S')) == 0)
529 			break;
530 
531 		init();
532 		if (i == 2)  {
533 			writel ("  Save.\n");
534 			cturn = 0;
535 			save (0);
536 		}
537 
538 							/* yes, reset game */
539 		wrboard();
540 	}
541 
542 	/* give him a chance to save if game was recovered */
543 	if (rfl && cturn)  {
544 		writel (svpromt);
545 		if (yorn (0))  {
546 							/* re-initialize for
547 							 * recovery */
548 			init();
549 			cturn = 0;
550 			save(0);
551 		}
552 	}
553 
554 							/* leave peacefully */
555 	getout ();
556 	/* NOTREACHED */
557 	return(0);
558 }
559