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