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 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