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