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