1 /* $OpenBSD: main.c,v 1.25 2021/10/23 11:22:48 mestre 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 <err.h>
33
34 #include "back.h"
35 #include "backlocal.h"
36
37 #define MVPAUSE 5 /* time to sleep when stuck */
38
39 extern const char *const instruct[]; /* text of instructions */
40
41 const char *const helpm[] = { /* help message */
42 "Enter a space or newline to roll, or",
43 " R to reprint the board\tD to double",
44 " S to save the game\tQ to quit",
45 0
46 };
47
48 const char *const contin[] = { /* pause message */
49 "(Type a newline to continue.)",
50 "",
51 0
52 };
53
54 /* *** Do game control through dm! ***
55 * static char user1a[] =
56 * "Sorry, you cannot play backgammon when there are more than ";
57 * static char user1b[] =
58 * " users\non the system.";
59 * static char user2a[] =
60 * "\nThere are now more than ";
61 * static char user2b[] =
62 * " users on the system, so you cannot play\nanother game. ";
63 */
64 static const char rules[] = "\nDo you want the rules of the game?";
65 static const char noteach[] = "Teachgammon not available!\n\007";
66 static const char need[] = "Do you need instructions for this program?";
67 static const char askcol[] =
68 "Enter 'r' to play red, 'w' to play white, 'b' to play both:";
69 static const char rollr[] = "Red rolls a ";
70 static const char rollw[] = ". White rolls a ";
71 static const char rstart[] = ". Red starts.\n";
72 static const char wstart[] = ". White starts.\n";
73 static const char toobad1[] = "Too bad, ";
74 static const char unable[] = " is unable to use that roll.\n";
75 static const char toobad2[] = ". Too bad, ";
76 static const char cantmv[] = " can't move.\n";
77 static const char bgammon[] = "Backgammon! ";
78 static const char gammon[] = "Gammon! ";
79 static const char again[] = ".\nWould you like to play again?";
80 static const char svpromt[] = "Would you like to save this game?";
81
82 int
main(int argc,char ** argv)83 main (int argc, char **argv)
84 {
85 int i,l; /* non-descript indices */
86 char c; /* non-descript character storage */
87
88 signal(SIGINT, getout); /* trap interrupts */
89
90 /* use whole screen for text */
91 begscr = 0;
92
93 getarg(argc, argv);
94
95 initcurses();
96
97 /* check if restored game and save flag for later */
98 if ((rfl = rflag)) {
99 if (pledge("stdio rpath wpath cpath tty", NULL) == -1)
100 err(1, "pledge");
101
102 wrboard(); /* print board */
103 /* if new game, pretend to be a non-restored game */
104 if (cturn == 0)
105 rflag = 0;
106 } else {
107 if (pledge("stdio rpath wpath cpath tty exec", NULL) == -1)
108 err(1, "pledge");
109
110 rscore = wscore = 0; /* zero score */
111
112 if (aflag) { /* print rules */
113 addstr(rules);
114 if (yorn(0)) {
115 endwin();
116 execl(TEACH, "teachgammon", (char *)NULL);
117
118 err(1, "%s", noteach);
119 } else {/* if not rules, then instructions */
120 addstr(need);
121 if (yorn(0)) { /* print instructions */
122 clear();
123 text(instruct);
124 }
125 }
126 }
127
128 if (pledge("stdio rpath wpath cpath tty", NULL) == -1)
129 err(1, "pledge");
130
131 init(); /* initialize board */
132
133 if (pnum == 2) {/* ask for color(s) */
134 printw("\n%s", askcol);
135 while (pnum == 2) {
136 c = readc();
137 switch (c) {
138
139 case 'R': /* red */
140 pnum = -1;
141 break;
142
143 case 'W': /* white */
144 pnum = 1;
145 break;
146
147 case 'B': /* both */
148 pnum = 0;
149 break;
150
151 case 'P': /* Control the dice */
152 iroll = 1;
153 addstr("\nDice controlled!\n");
154 addstr(askcol);
155 break;
156
157 default: /* error */
158 beep();
159 }
160 }
161 }
162
163 wrboard(); /* print board */
164
165 move(18, 0);
166 }
167 /* limit text to bottom of screen */
168 begscr = 17;
169
170 for (;;) { /* begin game! */
171 /* initial roll if needed */
172 if ((!rflag) || raflag)
173 roll();
174
175 /* perform ritual of first roll */
176 if (!rflag) {
177 move(17, 0);
178 while (D0 == D1) /* no doubles */
179 roll();
180
181 /* print rolls */
182 printw("%s%d%s%d", rollr, D0, rollw, D1);
183
184 /* winner goes first */
185 if (D0 > D1) {
186 addstr(rstart);
187 cturn = 1;
188 } else {
189 addstr(wstart);
190 cturn = -1;
191 }
192 }
193 /* initialize variables according to whose turn it is */
194
195 if (cturn == 1) { /* red */
196 home = 25;
197 bar = 0;
198 inptr = &in[1];
199 inopp = &in[0];
200 offptr = &off[1];
201 offopp = &off[0];
202 Colorptr = &color[1];
203 colorptr = &color[3];
204 colen = 3;
205 } else { /* white */
206 home = 0;
207 bar = 25;
208 inptr = &in[0];
209 inopp = &in[1];
210 offptr = &off[0];
211 offopp = &off[1];
212 Colorptr = &color[0];
213 colorptr = &color[2];
214 colen = 5;
215 }
216
217 /* do first move (special case) */
218 if (!(rflag && raflag)) {
219 if (cturn == pnum) /* computer's move */
220 domove(0);
221 else { /* player's move */
222 mvlim = movallow();
223 /* reprint roll */
224 move(cturn == -1 ? 18 : 19, 0);
225 proll();
226 getmove(); /* get player's move */
227 }
228 }
229 move(17, 0);
230 clrtoeol();
231 begscr = 18;
232 /* no longer any difference between normal and recovered game. */
233 rflag = 0;
234
235 /* move as long as it's someone's turn */
236 while (cturn == 1 || cturn == -1) {
237
238 /* board maintainence */
239 moveplayers(); /* fix board */
240
241 /* do computer's move */
242 if (cturn == pnum) {
243 domove(1);
244
245 /* see if double refused */
246 if (cturn == -2 || cturn == 2)
247 break;
248
249 /* check for winning move */
250 if (*offopp == 15) {
251 cturn *= -2;
252 break;
253 }
254 continue;
255
256 }
257 /* (player's move) */
258
259 /* clean screen if safe */
260 if (hflag) {
261 move(20, 0);
262 clrtobot();
263 hflag = 1;
264 }
265 /* if allowed, give him a chance to double */
266 if (dflag && dlast != cturn && gvalue < 64) {
267 move(cturn == -1 ? 18: 19, 0);
268 addstr(*Colorptr);
269 c = readc();
270
271 /* character cases */
272 switch (c) {
273
274 case 'R': /* reprint board */
275 wrboard();
276 break;
277
278 case 'S': /* save game */
279 raflag = 1;
280 save(1);
281 break;
282
283 case 'Q': /* quit */
284 quit();
285 break;
286
287 case 'D': /* double */
288 dble();
289 break;
290
291 case ' ': /* roll */
292 case '\n':
293 roll();
294 printw(" rolls %d %d. ", D0, D1);
295
296 /* see if he can move */
297 if ((mvlim = movallow()) == 0) {
298
299 /* can't move */
300 printw("%s%s%s", toobad1, *colorptr, unable);
301 if (pnum) {
302 moveplayers();
303 sleep(MVPAUSE);
304 }
305 nexturn();
306 break;
307 }
308
309 getmove();
310
311 /* okay to clean screen */
312 hflag = 1;
313 break;
314
315 default: /* invalid character */
316
317 /* print help message */
318 move(20, 0);
319 text(helpm);
320 move(cturn == -1 ? 18 : 19, 0);
321
322 /* don't erase */
323 hflag = 0;
324 }
325 } else {/* couldn't double */
326
327 /* print roll */
328 roll();
329 move(cturn == -1 ? 18: 19, 0);
330 proll();
331
332 /* can he move? */
333 if ((mvlim = movallow()) == 0) {
334
335 /* he can't */
336 printw("%s%s%s", toobad2, *colorptr, cantmv);
337 moveplayers();
338 sleep(MVPAUSE);
339 nexturn();
340 continue;
341 }
342
343 getmove();
344 }
345 }
346
347 /* don't worry about who won if quit */
348 if (cturn == 0)
349 break;
350
351 /* fix cturn = winner */
352 cturn /= -2;
353
354 /* final board pos. */
355 moveplayers();
356
357 /* backgammon? */
358 mflag = 0;
359 l = bar + 7 * cturn;
360 for (i = bar; i != l; i += cturn)
361 if (board[i] * cturn)
362 mflag++;
363
364 /* compute game value */
365 move(20, 0);
366 if (*offopp == 15) {
367 if (mflag) {
368 addstr(bgammon);
369 gvalue *= 3;
370 }
371 else if (*offptr <= 0) {
372 addstr(gammon);
373 gvalue *= 2;
374 }
375 }
376 /* report situation */
377 if (cturn == -1) {
378 addstr("Red wins ");
379 rscore += gvalue;
380 } else {
381 addstr("White wins ");
382 wscore += gvalue;
383 }
384 printw("%d point%s.\n", gvalue, (gvalue > 1) ? "s":"");
385
386 /* write score */
387 wrscore();
388
389 /* see if he wants another game */
390 addstr(again);
391 if ((i = yorn('S')) == 0)
392 break;
393
394 init();
395 if (i == 2) {
396 addstr(" Save.\n");
397 cturn = 0;
398 save(0);
399 }
400 /* yes, reset game */
401 wrboard();
402 }
403
404 /* give him a chance to save if game was recovered */
405 if (rfl && cturn) {
406 addstr(svpromt);
407 if (yorn(0)) {
408 /* re-initialize for recovery */
409 init();
410 cturn = 0;
411 save(0);
412 }
413 }
414 /* leave peacefully */
415 getout(0);
416 /* NOT REACHED */
417 }
418