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