less(1): Regenerate defines.h and update Makefile
[dragonfly.git] / games / backgammon / backgammon / main.c
blobe2394f02e6ee00c94a34fcd23184bdf2a9983397
1 /* @(#)main.c 8.1 (Berkeley) 5/31/93 */
2 /* $NetBSD: main.c,v 1.33 2019/02/03 10:45:58 mrg Exp $ */
4 /*
5 * Copyright (c) 1980, 1993
6 * The Regents of the University of California. All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
33 #include <time.h>
35 #include "back.h"
36 #include "backlocal.h"
38 #define MVPAUSE 5 /* time to sleep when stuck */
40 extern const char *const instr[]; /* text of instructions */
41 extern const char *const message[]; /* update message */
43 static const char *const helpm[] = { /* help message */
44 "Enter a space or newline to roll, or",
45 " R to reprint the board\tD to double",
46 " S to save the game\tQ to quit",
50 static const char *const contin[] = { /* pause message */
51 "(Type a newline to continue.)",
52 "",
55 static const char rules[] = "\nDo you want the rules of the game?";
56 static const char noteach[] = "Teachgammon not available!\n\a";
57 static const char need[] = "Do you need instructions for this program?";
58 static const char askcol[] =
59 "Enter 'r' to play red, 'w' to play white, 'b' to play both:";
60 static const char rollr[] = "Red rolls a ";
61 static const char rollw[] = ". White rolls a ";
62 static const char rstart[] = ". Red starts.\n";
63 static const char wstart[] = ". White starts.\n";
64 static const char toobad1[] = "Too bad, ";
65 static const char unable[] = " is unable to use that roll.\n";
66 static const char toobad2[] = ". Too bad, ";
67 static const char cantmv[] = " can't move.\n";
68 static const char bgammon[] = "Backgammon! ";
69 static const char gammon[] = "Gammon! ";
70 static const char again[] = ".\nWould you like to play again?";
71 static const char svpromt[] = "Would you like to save this game?";
73 static const char password[] = "losfurng";
74 static char pbuf[10];
76 int
77 main(int argc __unused, char **argv)
79 int i; /* non-descript index */
80 int l; /* non-descript index */
81 char c; /* non-descript character storage */
82 time_t t; /* time for random num generator */
83 struct move mmstore, *mm;
85 /* revoke setgid privileges */
86 setgid(getgid());
88 /* initialization */
89 bflag = 2; /* default no board */
90 signal(SIGINT, getout); /* trap interrupts */
91 if (tcgetattr(0, &old) == -1) /* get old tty mode */
92 errexit("backgammon(gtty)");
93 noech = old;
94 noech.c_lflag &= ~ECHO;
95 raw = noech;
96 raw.c_lflag &= ~ICANON; /* set up modes */
97 ospeed = cfgetospeed(&old); /* for termlib */
99 /* get terminal capabilities, and decide if it can cursor address */
100 tflag = getcaps(getenv("TERM"));
101 /* use whole screen for text */
102 if (tflag)
103 begscr = 0;
104 t = time(NULL);
105 srandom(t); /* 'random' seed */
107 /* need this now beceause getarg() may try to load a game */
108 mm = &mmstore;
109 move_init(mm);
110 while (*++argv != 0) /* process arguments */
111 getarg(mm, &argv);
112 args[acnt] = '\0';
113 if (tflag) { /* clear screen */
114 noech.c_oflag &= ~(ONLCR | OXTABS);
115 raw.c_oflag &= ~(ONLCR | OXTABS);
116 clear();
118 fixtty(&raw); /* go into raw mode */
120 /* check if restored game and save flag for later */
121 if ((rfl = rflag) != 0) {
122 wrtext(message); /* print message */
123 wrtext(contin);
124 wrboard(); /* print board */
125 /* if new game, pretend to be a non-restored game */
126 if (cturn == 0)
127 rflag = 0;
128 } else {
129 rscore = wscore = 0; /* zero score */
130 wrtext(message); /* update message without pausing */
132 if (aflag) { /* print rules */
133 writel(rules);
134 if (yorn(0)) {
136 fixtty(&old); /* restore tty */
137 execl(TEACH, "teachgammon", args[0]?args:0,
138 (char *) 0);
140 tflag = 0; /* error! */
141 writel(noteach);
142 exit(1);
143 } else {/* if not rules, then instructions */
144 writel(need);
145 if (yorn(0)) { /* print instructions */
146 clear();
147 wrtext(instr);
151 init(); /* initialize board */
153 if (pnum == 2) {/* ask for color(s) */
154 writec('\n');
155 writel(askcol);
156 while (pnum == 2) {
157 c = readc();
158 switch (c) {
160 case 'R': /* red */
161 pnum = -1;
162 break;
164 case 'W': /* white */
165 pnum = 1;
166 break;
168 case 'B': /* both */
169 pnum = 0;
170 break;
172 case 'P':
173 if (iroll)
174 break;
175 if (tflag)
176 curmove(curr, 0);
177 else
178 writec('\n');
179 writel("Password:");
180 signal(SIGALRM, getout);
181 cflag = 1;
182 alarm(10);
183 for (i = 0; i < 10; i++) {
184 pbuf[i] = readc();
185 if (pbuf[i] == '\n')
186 break;
188 if (i == 10)
189 while (readc() != '\n');
190 alarm(0);
191 cflag = 0;
192 if (i < 10)
193 pbuf[i] = '\0';
194 for (i = 0; i < 9; i++)
195 if (pbuf[i] != password[i])
196 getout(0);
197 iroll = 1;
198 if (tflag)
199 curmove(curr, 0);
200 else
201 writec('\n');
202 writel(askcol);
203 break;
205 default: /* error */
206 writec('\007');
209 } else
210 if (!aflag)
211 /* pause to read message */
212 wrtext(contin);
214 wrboard(); /* print board */
216 if (tflag)
217 curmove(18, 0);
218 else
219 writec('\n');
221 /* limit text to bottom of screen */
222 if (tflag)
223 begscr = 17;
225 for (;;) { /* begin game! */
226 /* initial roll if needed */
227 if ((!rflag) || raflag)
228 roll(mm);
230 /* perform ritual of first roll */
231 if (!rflag) {
232 if (tflag)
233 curmove(17, 0);
234 while (mm->D0 == mm->D1) /* no doubles */
235 roll(mm);
237 /* print rolls */
238 writel(rollr);
239 writec(mm->D0 + '0');
240 writel(rollw);
241 writec(mm->D1 + '0');
243 /* winner goes first */
244 if (mm->D0 > mm->D1) {
245 writel(rstart);
246 cturn = 1;
247 } else {
248 writel(wstart);
249 cturn = -1;
252 /* initialize variables according to whose turn it is */
254 if (cturn == 1) { /* red */
255 home = 25;
256 bar = 0;
257 inptr = &in[1];
258 inopp = &in[0];
259 offptr = &off[1];
260 offopp = &off[0];
261 Colorptr = &color[1];
262 colorptr = &color[3];
263 colen = 3;
264 } else { /* white */
265 home = 0;
266 bar = 25;
267 inptr = &in[0];
268 inopp = &in[1];
269 offptr = &off[0];
270 offopp = &off[1];
271 Colorptr = &color[0];
272 colorptr = &color[2];
273 colen = 5;
276 /* do first move (special case) */
277 if (!(rflag && raflag)) {
278 if (cturn == pnum) /* computer's move */
279 move(mm, 0);
280 else { /* player's move */
281 mm->mvlim = movallow(mm);
282 /* reprint roll */
283 if (tflag)
284 curmove(cturn == -1 ? 18 : 19, 0);
285 proll(mm);
286 getmove(mm); /* get player's move */
289 if (tflag) {
290 curmove(17, 0);
291 cline();
292 begscr = 18;
294 /* no longer any diff- erence between normal game and
295 * recovered game. */
296 rflag = 0;
298 /* move as long as it's someone's turn */
299 while (cturn == 1 || cturn == -1) {
301 /* board maintainence */
302 if (tflag)
303 refresh(); /* fix board */
304 else
305 /* redo board if -p */
306 if (cturn == bflag || bflag == 0)
307 wrboard();
309 /* do computer's move */
310 if (cturn == pnum) {
311 move(mm, 1);
313 /* see if double refused */
314 if (cturn == -2 || cturn == 2)
315 break;
317 /* check for winning move */
318 if (*offopp == 15) {
319 cturn *= -2;
320 break;
322 continue;
325 /* (player's move) */
327 /* clean screen if safe */
328 if (tflag && hflag) {
329 curmove(20, 0);
330 clend();
331 hflag = 1;
333 /* if allowed, give him a chance to double */
334 if (dlast != cturn && gvalue < 64) {
335 if (tflag)
336 curmove(cturn == -1 ? 18 : 19, 0);
337 writel(*Colorptr);
338 c = readc();
340 /* character cases */
341 switch (c) {
343 /* reprint board */
344 case 'R':
345 wrboard();
346 break;
348 /* save game */
349 case 'S':
350 raflag = 1;
351 save(mm, 1);
352 break;
354 /* quit */
355 case 'Q':
356 quit(mm);
357 break;
359 /* double */
360 case 'D':
361 dble();
362 break;
364 /* roll */
365 case ' ':
366 case '\n':
367 roll(mm);
368 writel(" rolls ");
369 writec(mm->D0 + '0');
370 writec(' ');
371 writec(mm->D1 + '0');
372 writel(". ");
374 /* see if he can move */
375 if ((mm->mvlim = movallow(mm)) == 0) {
377 /* can't move */
378 writel(toobad1);
379 writel(*colorptr);
380 writel(unable);
381 if (tflag) {
382 if (pnum) {
383 buflush();
384 sleep(MVPAUSE);
387 nexturn();
388 break;
390 /* get move */
391 getmove(mm);
393 /* okay to clean screen */
394 hflag = 1;
395 break;
397 /* invalid character */
398 default:
400 /* print help message */
401 if (tflag)
402 curmove(20, 0);
403 else
404 writec('\n');
405 wrtext(helpm);
406 if (tflag)
407 curmove(cturn == -1 ?
408 18 : 19, 0);
409 else
410 writec('\n');
412 /* don't erase */
413 hflag = 0;
415 } else {/* couldn't double */
417 /* print roll */
418 roll(mm);
419 if (tflag)
420 curmove(cturn == -1 ? 18 : 19, 0);
421 proll(mm);
423 /* can he move? */
424 if ((mm->mvlim = movallow(mm)) == 0) {
426 /* he can't */
427 writel(toobad2);
428 writel(*colorptr);
429 writel(cantmv);
430 buflush();
431 sleep(MVPAUSE);
432 nexturn();
433 continue;
435 /* get move */
436 getmove(mm);
440 /* don't worry about who won if quit */
441 if (cturn == 0)
442 break;
444 /* fix cturn = winner */
445 cturn /= -2;
447 /* final board pos. */
448 if (tflag)
449 refresh();
451 /* backgammon? */
452 mflag = 0;
453 l = bar + 7 * cturn;
454 for (i = bar; i != l; i += cturn)
455 if (board[i] && cturn)
456 mflag++;
458 /* compute game value */
459 if (tflag)
460 curmove(20, 0);
461 if (*offopp == 15 && (*offptr == 0 || *offptr == -15)) {
462 if (mflag) {
463 writel(bgammon);
464 gvalue *= 3;
465 } else {
466 writel(gammon);
467 gvalue *= 2;
470 /* report situation */
471 if (cturn == -1) {
472 writel("Red wins ");
473 rscore += gvalue;
474 } else {
475 writel("White wins ");
476 wscore += gvalue;
478 wrint(gvalue);
479 writel(" point");
480 if (gvalue > 1)
481 writec('s');
482 writel(".\n");
484 /* write score */
485 wrscore();
487 /* see if he wants another game */
488 writel(again);
489 if ((i = yorn('S')) == 0)
490 break;
492 init();
493 if (i == 2) {
494 writel(" Save.\n");
495 cturn = 0;
496 save(mm, 0);
498 /* yes, reset game */
499 wrboard();
502 /* give him a chance to save if game was recovered */
503 if (rfl && cturn) {
504 writel(svpromt);
505 if (yorn(0)) {
506 /* re-initialize for recovery */
507 init();
508 cturn = 0;
509 save(mm, 0);
512 /* leave peacefully */
513 getout(0);
514 /* NOTREACHED */
515 return (0);