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