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