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