Fix typo in MLINK name.
[dragonfly.git] / games / backgammon / backgammon / main.c
blob730cdd757a5c27fc040986ead70bc013b9175f42
1 /*-
2 * Copyright (c) 1980, 1993
3 * The Regents of the University of California. All rights reserved.
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. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
29 * @(#) Copyright (c) 1980, 1993 The Regents of the University of California. All rights reserved.
30 * @(#)main.c 8.1 (Berkeley) 5/31/93
31 * $FreeBSD: src/games/backgammon/backgammon/main.c,v 1.13 1999/11/30 03:48:22 billf Exp $
34 #include <stdio.h>
35 #include <termcap.h>
36 #include <unistd.h>
37 #include <string.h>
38 #include <stdlib.h>
39 #include <signal.h>
40 #include "back.h"
42 #define MVPAUSE 5 /* time to sleep when stuck */
43 #define MAXUSERS 35 /* maximum number of users */
45 extern const char *const instr[]; /* text of instructions */
46 extern const char *const message[]; /* update message */
48 const char *helpm[] = { /* help message */
49 "Enter a space or newline to roll, or",
50 " R to reprint the board\tD to double",
51 " S to save the game\tQ to quit",
55 const char *contin[] = { /* pause message */
56 "(Type a newline to continue.)",
57 "",
61 static const char rules[] = "\nDo you want the rules of the game?";
62 static const char noteach[] = "Teachgammon not available!\n\a";
63 static const char need[] = "Do you need instructions for this program?";
64 static const char askcol[] =
65 "Enter 'r' to play red, 'w' to play white, 'b' to play both:";
66 static const char rollr[] = "Red rolls a ";
67 static const char rollw[] = ". White rolls a ";
68 static const char rstart[] = ". Red starts.\n";
69 static const char wstart[] = ". White starts.\n";
70 static const char toobad1[] = "Too bad, ";
71 static const char unable[] = " is unable to use that roll.\n";
72 static const char toobad2[] = ". Too bad, ";
73 static const char cantmv[] = " can't move.\n";
74 static const char bgammon[] = "Backgammon! ";
75 static const char gammon[] = "Gammon! ";
76 static const char again[] = ".\nWould you like to play again?";
77 static const char svpromt[] = "Would you like to save this game?";
79 static const char password[] = "losfurng";
80 static char pbuf[10];
82 int
83 main(int argc, char **argv)
85 int i, l;
86 char c;
88 /* revoke privs */
89 setgid(getgid());
91 /* initialization */
92 bflag = 2; /* default no board */
93 acnt = 1; /* Number of args */
94 signal(SIGINT, getout); /* trap interrupts */
95 if (tcgetattr(0, &tty) == -1) /* get old tty mode */
96 errexit("backgammon(tcgetattr)");
97 old = tty.c_lflag;
98 bgraw = ((noech = old & ~ECHO) & ~ICANON); /* set up modes */
99 ospeed = cfgetospeed(&tty); /* for termlib */
101 /* get terminal capabilities, and decide if it can cursor address */
102 tflag = getcaps(getenv("TERM"));
103 /* use whole screen for text */
104 if (tflag)
105 begscr = 0;
106 srandomdev();
108 getarg(argc, argv);
109 args[acnt] = NULL;
110 if (tflag) { /* clear screen */
111 noech &= ~(ICRNL | OXTABS);
112 bgraw &= ~(ICRNL | OXTABS);
113 clear();
115 fixtty(bgraw); /* go into raw mode */
117 /* check if restored game and save flag for later */
118 if ((rfl = rflag) != 0) {
119 text(message); /* print message */
120 text(contin);
121 wrboard(); /* print board */
122 /* if new game, pretend
123 * to be a non-restored game
125 if (cturn == 0)
126 rflag = 0;
127 } else {
128 rscore = wscore = 0; /* zero score */
129 text(message); /* update message
130 * without pausing */
132 if (aflag) { /* print rules */
133 writel(rules);
134 if (yorn(0)) {
135 fixtty(old); /* restore tty */
136 args[0] = strdup("teachgammon");
137 execv(TEACH, args);
139 tflag = 0; /* error! */
140 writel(noteach);
141 exit(1);
142 } else { /* if not rules, then
143 * instructions
145 writel(need);
146 if (yorn(0)) { /* print instructions */
147 clear();
148 text(instr);
153 for (i = 0; i < acnt; i++)
154 free(args[i]);
156 init(); /* initialize board */
158 if (pnum == 2) { /* ask for color(s) */
159 writec('\n');
160 writel(askcol);
161 while (pnum == 2) {
162 c = readc();
163 switch (c) {
164 case 'R': /* red */
165 pnum = -1;
166 break;
168 case 'W': /* white */
169 pnum = 1;
170 break;
172 case 'B': /* both */
173 pnum = 0;
174 break;
176 case 'P':
177 if (iroll)
178 break;
179 if (tflag)
180 curmove(curr, 0);
181 else
182 writec('\n');
183 writel("Password:");
184 signal(SIGALRM, getout);
185 cflag = 1;
186 alarm(10);
187 for (i = 0; i < 10; i++) {
188 pbuf[i] = readc();
189 if (pbuf[i] == '\n')
190 break;
192 if (i == 10)
193 while (readc() != '\n');
194 alarm(0);
195 cflag = 0;
196 if (i < 10)
197 pbuf[i] = '\0';
198 for (i = 0; i < 9; i++)
199 if (pbuf[i] != password[i])
200 getout(0);
201 iroll = 1;
202 if (tflag)
203 curmove(curr, 0);
204 else
205 writec('\n');
206 writel(askcol);
207 break;
209 default: /* error */
210 writec('\007');
213 } else
214 if (!aflag)
215 /* pause to read message */
216 text(contin);
218 wrboard(); /* print board */
220 if (tflag)
221 curmove(18, 0);
222 else
223 writec('\n');
225 /* limit text to bottom of screen */
226 if (tflag)
227 begscr = 17;
229 for (;;) { /* begin game! */
230 /* initial roll if needed */
231 if ((!rflag) || raflag)
232 roll();
234 /* perform ritual of first roll */
235 if (!rflag) {
236 if (tflag)
237 curmove(17, 0);
238 while (D0 == D1) /* no doubles */
239 roll();
241 /* print rolls */
242 writel(rollr);
243 writec(D0 + '0');
244 writel(rollw);
245 writec(D1 + '0');
247 /* winner goes first */
248 if (D0 > D1) {
249 writel(rstart);
250 cturn = 1;
251 } else {
252 writel(wstart);
253 cturn = -1;
257 /* initialize variables according to whose turn it is */
258 if (cturn == 1) { /* red */
259 home = 25;
260 bar = 0;
261 inptr = &in[1];
262 inopp = &in[0];
263 offptr = &off[1];
264 offopp = &off[0];
265 Colorptr = &color[1];
266 colorptr = &color[3];
267 colen = 3;
268 } else { /* white */
269 home = 0;
270 bar = 25;
271 inptr = &in[0];
272 inopp = &in[1];
273 offptr = &off[0];
274 offopp = &off[1];
275 Colorptr = &color[0];
276 colorptr = &color[2];
277 colen = 5;
280 /* do first move (special case) */
281 if (!(rflag && raflag)) {
282 if (cturn == pnum) /* computer's move */
283 move(0);
284 else { /* player's move */
285 mvlim = movallow();
286 /* reprint roll */
287 if (tflag)
288 curmove(cturn == -1 ? 18 : 19, 0);
289 proll();
290 getmove(); /* get player's move */
293 if (tflag) {
294 curmove(17, 0);
295 cline();
296 begscr = 18;
299 /* no longer any difference between normal and recovered game. */
300 rflag = 0;
302 /* move as long as it's someone's turn */
303 while (cturn == 1 || cturn == -1) {
304 /* board maintenance */
305 if (tflag)
306 refresh(); /* fix board */
307 else
308 /* redo board if -p */
309 if (cturn == bflag || bflag == 0)
310 wrboard();
312 /* do computer's move */
313 if (cturn == pnum) {
314 move(1);
316 /* see if double refused */
317 if (cturn == -2 || cturn == 2)
318 break;
320 /* check for winning move */
321 if (*offopp == 15) {
322 cturn *= -2;
323 break;
325 continue;
328 /* (player's move) */
330 /* clean screen if safe */
331 if (tflag && hflag) {
332 curmove(20, 0);
333 clend();
334 hflag = 1;
337 /* if allowed, give him a chance to double */
338 if (dlast != cturn && gvalue < 64) {
339 if (tflag)
340 curmove(cturn == -1 ? 18 : 19, 0);
341 writel(*Colorptr);
342 c = readc();
344 /* character cases */
345 switch (c) {
346 case 'R': /* reprint board */
347 wrboard();
348 break;
350 case 'S': /* save game */
351 raflag = 1;
352 save(1);
353 break;
355 case 'Q': /* quit */
356 quit();
357 break;
359 case 'D': /* double */
360 dble();
361 break;
363 case ' ': /* roll */
364 case '\n':
365 roll();
366 writel(" rolls ");
367 writec(D0 + '0');
368 writec(' ');
369 writec(D1 + '0');
370 writel(". ");
372 /* see if he can move */
373 if ((mvlim = movallow()) == 0) {
374 /* can't move */
375 writel(toobad1);
376 writel(*colorptr);
377 writel(unable);
378 if (tflag) {
379 if (pnum) {
380 buflush();
381 sleep(MVPAUSE);
384 nexturn();
385 break;
388 /* get move */
389 getmove();
391 /* okay to clean screen */
392 hflag = 1;
393 break;
395 /* invalid character */
396 default:
398 /* print help message */
399 if (tflag)
400 curmove(20, 0);
401 else
402 writec('\n');
403 text(helpm);
404 if (tflag)
405 curmove(cturn == -1 ? 18 : 19,
407 else
408 writec('\n');
410 /* don't erase */
411 hflag = 0;
413 } else { /* couldn't double */
414 /* print roll */
415 roll();
416 if (tflag)
417 curmove(cturn == -1 ? 18 : 19, 0);
418 proll();
420 /* can he move? */
421 if ((mvlim = movallow()) == 0) {
422 /* he can't */
423 writel(toobad2);
424 writel(*colorptr);
425 writel(cantmv);
426 buflush();
427 sleep(MVPAUSE);
428 nexturn();
429 continue;
432 /* get move */
433 getmove();
437 /* don't worry about who won if quit */
438 if (cturn == 0)
439 break;
441 /* fix cturn = winner */
442 cturn /= -2;
444 /* final board pos. */
445 if (tflag)
446 refresh();
448 /* backgammon? */
449 mflag = 0;
450 l = bar + 7 * cturn;
451 for (i = bar; i != l; i += cturn)
452 if (board[i] && cturn)
453 mflag++;
455 /* compute game value */
456 if (tflag)
457 curmove(20, 0);
458 if (*offopp == 15) {
459 if (mflag) {
460 writel(bgammon);
461 gvalue *= 3;
462 } else
463 if (*offptr <= 0) {
464 writel(gammon);
465 gvalue *= 2;
469 /* report situation */
470 if (cturn == -1) {
471 writel("Red wins ");
472 rscore += gvalue;
473 } else {
474 writel("White wins ");
475 wscore += gvalue;
477 wrint(gvalue);
478 writel(" point");
479 if (gvalue > 1)
480 writec('s');
481 writel(".\n");
483 /* write score */
484 wrscore();
486 /* see if he wants another game */
487 writel(again);
488 if ((i = yorn('S')) == 0)
489 break;
491 init();
492 if (i == 2) {
493 writel(" Save.\n");
494 cturn = 0;
495 save(0);
498 /* yes, reset game */
499 wrboard();
502 /* give him a chance to save if game was recovered */
503 if (rfl && cturn) {
504 writel(svpromt);
505 if (yorn(0)) {
506 /* re-initialize for recovery */
507 init();
508 cturn = 0;
509 save(0);
513 /* leave peacefully */
514 getout(0);
515 /* NOTREACHED */
516 return (0);