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