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