1/*	$NetBSD: main.c,v 1.27 2009/08/12 05:17:57 dholland 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
40static char sccsid[] = "@(#)main.c	8.1 (Berkeley) 5/31/93";
41#else
42__RCSID("$NetBSD: main.c,v 1.27 2009/08/12 05:17:57 dholland 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
53extern const char   *const instr[];		/* text of instructions */
54extern const char   *const message[];		/* update message */
55extern short ospeed;			/* tty output speed */
56
57static 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
64static const char *const contin[] = {		/* pause message */
65	"(Type a newline to continue.)",
66	"",
67	0
68};
69static const char rules[] = "\nDo you want the rules of the game?";
70static const char noteach[] = "Teachgammon not available!\n\a";
71static const char need[] = "Do you need instructions for this program?";
72static const char askcol[] =
73"Enter 'r' to play red, 'w' to play white, 'b' to play both:";
74static const char rollr[] = "Red rolls a ";
75static const char rollw[] = ".  White rolls a ";
76static const char rstart[] = ".  Red starts.\n";
77static const char wstart[] = ".  White starts.\n";
78static const char toobad1[] = "Too bad, ";
79static const char unable[] = " is unable to use that roll.\n";
80static const char toobad2[] = ".  Too bad, ";
81static const char cantmv[] = " can't move.\n";
82static const char bgammon[] = "Backgammon!  ";
83static const char gammon[] = "Gammon!  ";
84static const char again[] = ".\nWould you like to play again?";
85static const char svpromt[] = "Would you like to save this game?";
86
87static const char password[] = "losfurng";
88static char pbuf[10];
89
90int
91main(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