Merge branch 'vendor/FILE'
[dragonfly.git] / games / backgammon / backgammon / main.c
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. 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.
16  *
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.
28  *
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 $
32  */
33
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"
41
42 #define MVPAUSE 5                               /* time to sleep when stuck */
43 #define MAXUSERS 35                             /* maximum number of users */
44
45 extern const char       *const instr[];         /* text of instructions */
46 extern const char       *const message[];       /* update message */
47
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",
52         0
53 };
54
55 const char      *contin[] = {                   /* pause message */
56         "(Type a newline to continue.)",
57         "",
58         0
59 };
60
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?";
78
79 static const char       password[] = "losfurng";
80 static char     pbuf[10];
81
82 int
83 main(int argc, char **argv)
84 {
85         int i, l;
86         char c;
87
88         /* revoke privs */
89         setgid(getgid());
90
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         raw = ((noech = old & ~ECHO) & ~ICANON); /* set up modes */
99         ospeed = cfgetospeed(&tty);             /* for termlib */
100
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();
107
108         getarg(argc, argv);
109         args[acnt] = NULL;
110         if (tflag) {                            /* clear screen */
111                 noech &= ~(ICRNL | OXTABS);
112                 raw &= ~(ICRNL | OXTABS);
113                 clear();
114         }
115         fixtty(raw);                            /* go into raw mode */
116
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
124                                                  */
125                 if (cturn == 0)
126                         rflag = 0;
127         } else {
128                 rscore = wscore = 0;            /* zero score */
129                 text(message);                  /* update message
130                                                          * without pausing */
131
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);
138
139                                 tflag = 0;      /* error! */
140                                 writel(noteach);
141                                 exit(1);
142                         } else {                /* if not rules, then
143                                                  * instructions
144                                                  */
145                                 writel(need);
146                                 if (yorn(0)) {  /* print instructions */
147                                         clear();
148                                         text(instr);
149                                 }
150                         }
151                 }
152
153                 for (i = 0; i < acnt; i++)
154                         free(args[i]);
155
156                 init();                         /* initialize board */
157
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;
167
168                                 case 'W':       /* white */
169                                         pnum = 1;
170                                         break;
171
172                                 case 'B':       /* both */
173                                         pnum = 0;
174                                         break;
175
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;
191                                         }
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;
208
209                                 default:        /* error */
210                                         writec('\007');
211                                 }
212                         }
213                 } else
214                         if (!aflag)
215                                 /* pause to read message */
216                                 text(contin);
217
218                 wrboard();                      /* print board */
219
220                 if (tflag)
221                         curmove(18, 0);
222                 else
223                         writec('\n');
224         }
225         /* limit text to bottom of screen */
226         if (tflag)
227                 begscr = 17;
228
229         for (;;) {                              /* begin game! */
230                 /* initial roll if needed */
231                 if ((!rflag) || raflag)
232                         roll();
233
234                 /* perform ritual of first roll */
235                 if (!rflag) {
236                         if (tflag)
237                                 curmove(17, 0);
238                         while (D0 == D1)        /* no doubles */
239                                 roll();
240
241                         /* print rolls */
242                         writel(rollr);
243                         writec(D0 + '0');
244                         writel(rollw);
245                         writec(D1 + '0');
246
247                         /* winner goes first */
248                         if (D0 > D1) {
249                                 writel(rstart);
250                                 cturn = 1;
251                         } else {
252                                 writel(wstart);
253                                 cturn = -1;
254                         }
255                 }
256
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;
278                 }
279
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 */
291                         }
292                 }
293                 if (tflag) {
294                         curmove(17, 0);
295                         cline();
296                         begscr = 18;
297                 }
298
299                 /* no longer any difference between normal and recovered game. */
300                 rflag = 0;
301
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();
311
312                         /* do computer's move */
313                         if (cturn == pnum) {
314                                 move(1);
315
316                                 /* see if double refused */
317                                 if (cturn == -2 || cturn == 2)
318                                         break;
319
320                                 /* check for winning move */
321                                 if (*offopp == 15) {
322                                         cturn *= -2;
323                                         break;
324                                 }
325                                 continue;
326                         }
327
328                         /* (player's move) */
329
330                         /* clean screen if safe */
331                         if (tflag && hflag) {
332                                 curmove(20, 0);
333                                 clend();
334                                 hflag = 1;
335                         }
336
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();
343
344                                 /* character cases */
345                                 switch (c) {
346                                 case 'R':               /* reprint board */
347                                         wrboard();
348                                         break;
349
350                                 case 'S':               /* save game */
351                                         raflag = 1;
352                                         save(1);
353                                         break;
354
355                                 case 'Q':               /* quit */
356                                         quit();
357                                         break;
358
359                                 case 'D':               /* double */
360                                         dble();
361                                         break;
362
363                                 case ' ':               /* roll */
364                                 case '\n':
365                                         roll();
366                                         writel(" rolls ");
367                                         writec(D0 + '0');
368                                         writec(' ');
369                                         writec(D1 + '0');
370                                         writel(".  ");
371
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);
382                                                         }
383                                                 }
384                                                 nexturn();
385                                                 break;
386                                         }
387
388                                         /* get move */
389                                         getmove();
390
391                                         /* okay to clean screen */
392                                         hflag = 1;
393                                         break;
394
395                                 /* invalid character */
396                                 default:
397
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,
406                                                         0);
407                                         else
408                                                 writec('\n');
409
410                                         /* don't erase */
411                                         hflag = 0;
412                                 }
413                         } else {                /* couldn't double */
414                                                 /* print roll */
415                                 roll();
416                                 if (tflag)
417                                         curmove(cturn == -1 ? 18 : 19, 0);
418                                 proll();
419
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;
430                                 }
431
432                                 /* get move */
433                                 getmove();
434                         }
435                 }
436
437                 /* don't worry about who won if quit */
438                 if (cturn == 0)
439                         break;
440
441                 /* fix cturn = winner */
442                 cturn /= -2;
443
444                 /* final board pos. */
445                 if (tflag)
446                         refresh();
447
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++;
454
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;
466                                 }
467                 }
468
469                 /* report situation */
470                 if (cturn == -1) {
471                         writel("Red wins ");
472                         rscore += gvalue;
473                 } else {
474                         writel("White wins ");
475                         wscore += gvalue;
476                 }
477                 wrint(gvalue);
478                 writel(" point");
479                 if (gvalue > 1)
480                         writec('s');
481                 writel(".\n");
482
483                 /* write score */
484                 wrscore();
485
486                 /* see if he wants another game */
487                 writel(again);
488                 if ((i = yorn('S')) == 0)
489                         break;
490
491                 init();
492                 if (i == 2) {
493                         writel("  Save.\n");
494                         cturn = 0;
495                         save(0);
496                 }
497
498                 /* yes, reset game */
499                 wrboard();
500         }
501
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);
510                 }
511         }
512
513         /* leave peacefully */
514         getout(0);
515         /* NOTREACHED */
516         return (0);
517 }