1/* $NetBSD: main.c,v 1.27 2009/08/12 05:17:57 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 40static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 5/31/93"; 41#else 42__RCSID("$NetBSD: main.c,v 1.27 2009/08/12 05:17:57 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 53extern const char *const instr[]; /* text of instructions */ 54extern const char *const message[]; /* update message */ 55extern short ospeed; /* tty output speed */ 56 57static 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 64static const char *const contin[] = { /* pause message */ 65 "(Type a newline to continue.)", 66 "", 67 0 68}; 69static const char rules[] = "\nDo you want the rules of the game?"; 70static const char noteach[] = "Teachgammon not available!\n\a"; 71static const char need[] = "Do you need instructions for this program?"; 72static const char askcol[] = 73"Enter 'r' to play red, 'w' to play white, 'b' to play both:"; 74static const char rollr[] = "Red rolls a "; 75static const char rollw[] = ". White rolls a "; 76static const char rstart[] = ". Red starts.\n"; 77static const char wstart[] = ". White starts.\n"; 78static const char toobad1[] = "Too bad, "; 79static const char unable[] = " is unable to use that roll.\n"; 80static const char toobad2[] = ". Too bad, "; 81static const char cantmv[] = " can't move.\n"; 82static const char bgammon[] = "Backgammon! "; 83static const char gammon[] = "Gammon! "; 84static const char again[] = ".\nWould you like to play again?"; 85static const char svpromt[] = "Would you like to save this game?"; 86 87static const char password[] = "losfurng"; 88static char pbuf[10]; 89 90int 91main(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 wrtext(message); /* print message */ 137 wrtext(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 wrtext(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 wrtext(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 wrtext(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 wrtext(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} 531