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