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