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