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