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