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 * @(#)move.c 8.1 (Berkeley) 5/31/93 30 * $FreeBSD: src/games/backgammon/backgammon/move.c,v 1.5 1999/11/30 03:48:23 billf Exp $ 31 */ 32 33 #include "back.h" 34 35 #ifdef DEBUG 36 #include <stdio.h> 37 FILE *trace; 38 static char tests[20]; 39 #endif 40 41 static void trymove(int, int); 42 static struct BOARD *bsave(void); 43 static void binsert(struct BOARD *); 44 static int bcomp(struct BOARD *, struct BOARD *); 45 static void mvcheck(struct BOARD *, struct BOARD *); 46 static void makefree(struct BOARD *); 47 static struct BOARD *nextfree(void); 48 static void pickmove(void); 49 static void boardcopy(struct BOARD *); 50 static void movcmp(void); 51 static int movegood(void); 52 53 struct BOARD { /* structure of game position */ 54 int b_board[26]; /* board position */ 55 int b_in[2]; /* men in */ 56 int b_off[2]; /* men off */ 57 int b_st[4], b_fn[4]; /* moves */ 58 59 struct BOARD *b_next; /* forward queue pointer */ 60 }; 61 62 struct BOARD *freeq = NULL; 63 struct BOARD *checkq = NULL; 64 65 /* these variables are values for the candidate move */ 66 static int ch; /* chance of being hit */ 67 static int op; /* computer's open men */ 68 static int pt; /* comp's protected points */ 69 static int em; /* farthest man back */ 70 static int frc; /* chance to free comp's men */ 71 static int frp; /* chance to free pl's men */ 72 73 /* these values are the values for the move chosen (so far) */ 74 static int chance; /* chance of being hit */ 75 static int openmen; /* computer's open men */ 76 static int points; /* comp's protected points */ 77 static int endman; /* farthest man back */ 78 static int barmen; /* men on bar */ 79 static int menin; /* men in inner table */ 80 static int menoff; /* men off board */ 81 static int oldfrc; /* chance to free comp's men */ 82 static int oldfrp; /* chance to free pl's men */ 83 84 static int cp[5]; /* candidate start position */ 85 static int cg[5]; /* candidate finish position */ 86 87 static int race; /* game reduced to a race */ 88 89 /* zero if first move */ 90 void 91 move(int okay) 92 { 93 int i; /* index */ 94 int l; /* last man */ 95 96 l = 0; 97 if (okay) { 98 /* see if comp should double */ 99 if (gvalue < 64 && dlast != cturn && dblgood()) { 100 writel(*Colorptr); 101 dble(); /* double */ 102 /* return if declined */ 103 if (cturn != 1 && cturn != -1) 104 return; 105 } 106 roll(); 107 } 108 109 race = 0; 110 for (i = 0; i < 26; i++) { 111 if (board[i] < 0) 112 l = i; 113 } 114 for (i = 0; i < l; i++) { 115 if (board[i] > 0) 116 break; 117 } 118 if (i == l) 119 race = 1; 120 121 /* print roll */ 122 if (tflag) 123 curmove(cturn == -1 ? 18 : 19, 0); 124 writel(*Colorptr); 125 writel(" rolls "); 126 writec(D0 + '0'); 127 writec(' '); 128 writec(D1 + '0'); 129 /* make tty interruptable while thinking */ 130 if (tflag) 131 cline(); 132 fixtty(noech); 133 134 /* find out how many moves */ 135 mvlim = movallow(); 136 if (mvlim == 0) { 137 writel(" but cannot use it.\n"); 138 nexturn(); 139 fixtty(bgraw); 140 return; 141 } 142 143 /* initialize */ 144 for (i = 0; i < 4; i++) 145 cp[i] = cg[i] = 0; 146 147 /* strategize */ 148 trymove(0, 0); 149 pickmove(); 150 151 /* print move */ 152 writel(" and moves "); 153 for (i = 0; i < mvlim; i++) { 154 if (i > 0) 155 writec(','); 156 wrint(p[i] = cp[i]); 157 writec('-'); 158 wrint(g[i] = cg[i]); 159 makmove(i); 160 } 161 writec('.'); 162 163 /* print blots hit */ 164 if (tflag) 165 curmove(20, 0); 166 else 167 writec('\n'); 168 for (i = 0; i < mvlim; i++) 169 if (h[i]) 170 wrhit(g[i]); 171 /* get ready for next move */ 172 nexturn(); 173 if (!okay) { 174 buflush(); 175 sleep(3); 176 } 177 fixtty(bgraw); /* no more tty interrupt */ 178 } 179 180 /* 181 * mvnum is number of move (rel zero) 182 * see if swapped also tested 183 */ 184 static void 185 trymove(int mvnum, int swapped) 186 { 187 int pos; /* position on board */ 188 int rval; /* value of roll */ 189 190 /* if recursed through all dice values, compare move */ 191 if (mvnum == mvlim) { 192 binsert(bsave()); 193 return; 194 } 195 196 /* make sure dice in always same order */ 197 if (d0 == swapped) 198 swap; 199 /* choose value for this move */ 200 rval = dice[mvnum != 0]; 201 202 /* find all legitimate moves */ 203 for (pos = bar; pos != home; pos += cturn) { 204 /* fix order of dice */ 205 if (d0 == swapped) 206 swap; 207 /* break if stuck on bar */ 208 if (board[bar] != 0 && pos != bar) 209 break; 210 /* on to next if not occupied */ 211 if (board[pos] * cturn <= 0) 212 continue; 213 /* set up arrays for move */ 214 p[mvnum] = pos; 215 g[mvnum] = pos + rval * cturn; 216 if (g[mvnum] * cturn >= home) { 217 if (*offptr < 0) 218 break; 219 g[mvnum] = home; 220 } 221 /* try to move */ 222 if (makmove(mvnum)) 223 continue; 224 else 225 trymove(mvnum + 1, 2); 226 /* undo move to try another */ 227 backone(mvnum); 228 } 229 230 /* swap dice and try again */ 231 if ((!swapped) && D0 != D1) 232 trymove(0, 1); 233 } 234 235 static struct BOARD * 236 bsave(void) 237 { 238 int i; /* index */ 239 struct BOARD *now; /* current position */ 240 241 now = nextfree(); /* get free BOARD */ 242 243 /* store position */ 244 for (i = 0; i < 26; i++) 245 now->b_board[i] = board[i]; 246 now->b_in[0] = in[0]; 247 now->b_in[1] = in[1]; 248 now->b_off[0] = off[0]; 249 now->b_off[1] = off[1]; 250 for (i = 0; i < mvlim; i++) { 251 now->b_st[i] = p[i]; 252 now->b_fn[i] = g[i]; 253 } 254 return (now); 255 } 256 257 static void 258 binsert(struct BOARD *new) 259 { 260 int result; /* comparison result */ 261 struct BOARD *qp; /* queue pointer */ 262 263 qp = checkq; 264 if (qp == NULL) { /* check if queue empty */ 265 checkq = qp = new; 266 qp->b_next = NULL; 267 return; 268 } 269 result = bcomp(new, qp); /* compare to first element */ 270 if (result < 0) { /* insert in front */ 271 new->b_next = qp; 272 checkq = new; 273 return; 274 } 275 if (result == 0) { /* duplicate entry */ 276 mvcheck(qp, new); 277 makefree(new); 278 return; 279 } 280 while (qp->b_next != NULL) { /* traverse queue */ 281 result = bcomp(new, qp->b_next); 282 if (result < 0) { /* found place */ 283 new->b_next = qp->b_next; 284 qp->b_next = new; 285 return; 286 } 287 if (result == 0) { /* duplicate entry */ 288 mvcheck(qp->b_next, new); 289 makefree(new); 290 return; 291 } 292 qp = qp->b_next; 293 } 294 /* place at end of queue */ 295 qp->b_next = new; 296 new->b_next = NULL; 297 } 298 299 static int 300 bcomp(struct BOARD *a, struct BOARD *b) 301 { 302 int *aloc = a->b_board; /* pointer to board a */ 303 int *bloc = b->b_board; /* pointer to board b */ 304 int i; /* index */ 305 int result; /* comparison result */ 306 307 for (i = 0; i < 26; i++) { /* compare boards */ 308 result = cturn * (aloc[i] - bloc[i]); 309 if (result) 310 return (result); /* found inequality */ 311 } 312 return (0); /* same position */ 313 } 314 315 static void 316 mvcheck(struct BOARD *incumbent, struct BOARD *candidate) 317 { 318 int i; 319 int result; 320 321 for (i = 0; i < mvlim; i++) { 322 result = cturn * (candidate->b_st[i] - incumbent->b_st[i]); 323 if (result > 0) 324 return; 325 if (result < 0) 326 break; 327 } 328 if (i == mvlim) 329 return; 330 for (i = 0; i < mvlim; i++) { 331 incumbent->b_st[i] = candidate->b_st[i]; 332 incumbent->b_fn[i] = candidate->b_fn[i]; 333 } 334 } 335 336 static void 337 makefree(struct BOARD *dead) 338 { 339 dead->b_next = freeq; /* add to freeq */ 340 freeq = dead; 341 } 342 343 static struct BOARD * 344 nextfree(void) 345 { 346 struct BOARD *new; 347 348 if (freeq == NULL) { 349 new = calloc(1, sizeof(struct BOARD)); 350 if (new == NULL) { 351 writel("\nOut of memory\n"); 352 getout(0); 353 } 354 new->b_next = NULL; 355 } else { 356 new = freeq; 357 freeq = freeq->b_next; 358 } 359 return (new); 360 } 361 362 static void 363 pickmove(void) 364 { 365 /* current game position */ 366 struct BOARD *now = bsave(); 367 struct BOARD *next; /* next move */ 368 369 #ifdef DEBUG 370 if (trace == NULL) 371 trace = fopen("bgtrace", "w"); 372 fprintf(trace, "\nRoll: %d %d%s\n", D0, D1, race ? " (race)" : ""); 373 fflush(trace); 374 #endif 375 do { /* compare moves */ 376 boardcopy(checkq); 377 next = checkq->b_next; 378 makefree(checkq); 379 checkq = next; 380 movcmp(); 381 } while (checkq != NULL); 382 383 boardcopy(now); 384 } 385 386 static void 387 boardcopy(struct BOARD *s) 388 { 389 int i; /* index */ 390 391 for (i = 0; i < 26; i++) 392 board[i] = s->b_board[i]; 393 for (i = 0; i < 2; i++) { 394 in[i] = s->b_in[i]; 395 off[i] = s->b_off[i]; 396 } 397 for (i = 0; i < mvlim; i++) { 398 p[i] = s->b_st[i]; 399 g[i] = s->b_fn[i]; 400 } 401 } 402 403 static void 404 movcmp(void) 405 { 406 int i; 407 408 #ifdef DEBUG 409 if (trace == NULL) 410 trace = fopen("bgtrace", "w"); 411 #endif 412 413 odds(0, 0, 0); 414 if (!race) { 415 ch = op = pt = 0; 416 for (i = 1; i < 25; i++) { 417 if (board[i] == cturn) 418 ch = canhit(i, 1); 419 op += abs(bar - i); 420 } 421 for (i = bar + cturn; i != home; i += cturn) 422 if (board[i] * cturn > 1) 423 pt += abs(bar - i); 424 frc = freemen(bar) + trapped(bar, cturn); 425 frp = freemen(home) + trapped(home, -cturn); 426 } 427 for (em = bar; em != home; em += cturn) 428 if (board[em] * cturn > 0) 429 break; 430 em = abs(home - em); 431 #ifdef DEBUG 432 fputs("Board: ", trace); 433 for (i = 0; i < 26; i++) 434 fprintf(trace, " %d", board[i]); 435 if (race) 436 fprintf(trace, "\n\tem = %d\n", em); 437 else 438 fprintf(trace, 439 "\n\tch = %d, pt = %d, em = %d, frc = %d, frp = %d\n", 440 ch, pt, em, frc, frp); 441 fputs("\tMove: ", trace); 442 for (i = 0; i < mvlim; i++) 443 fprintf(trace, " %d-%d", p[i], g[i]); 444 fputs("\n", trace); 445 fflush(trace); 446 strcpy(tests, ""); 447 #endif 448 if ((cp[0] == 0 && cg[0] == 0) || movegood()) { 449 #ifdef DEBUG 450 fprintf(trace, "\t[%s] ... wins.\n", tests); 451 fflush(trace); 452 #endif 453 for (i = 0; i < mvlim; i++) { 454 cp[i] = p[i]; 455 cg[i] = g[i]; 456 } 457 if (!race) { 458 chance = ch; 459 openmen = op; 460 points = pt; 461 endman = em; 462 barmen = abs(board[home]); 463 oldfrc = frc; 464 oldfrp = frp; 465 } 466 menin = *inptr; 467 menoff = *offptr; 468 } 469 #ifdef DEBUG 470 else { 471 fprintf(trace, "\t[%s] ... loses.\n", tests); 472 fflush(trace); 473 } 474 #endif 475 } 476 477 static int 478 movegood(void) 479 { 480 int n; 481 482 if (*offptr == 15) 483 return (1); 484 if (menoff == 15) 485 return (0); 486 if (race) { 487 #ifdef DEBUG 488 strcat(tests, "o"); 489 #endif 490 if (*offptr - menoff) 491 return (*offptr > menoff); 492 #ifdef DEBUG 493 strcat(tests, "e"); 494 #endif 495 if (endman - em) 496 return (endman > em); 497 #ifdef DEBUG 498 strcat(tests, "i"); 499 #endif 500 if (menin == 15) 501 return (0); 502 if (*inptr == 15) 503 return (1); 504 #ifdef DEBUG 505 strcat(tests, "i"); 506 #endif 507 if (*inptr - menin) 508 return (*inptr > menin); 509 return (rnum(2)); 510 } else { 511 n = barmen - abs(board[home]); 512 #ifdef DEBUG 513 strcat(tests, "c"); 514 #endif 515 if (abs(chance - ch) + 25 * n > rnum(150)) 516 return (n ? (n < 0) : (ch < chance)); 517 #ifdef DEBUG 518 strcat(tests, "o"); 519 #endif 520 if (*offptr - menoff) 521 return (*offptr > menoff); 522 #ifdef DEBUG 523 strcat(tests, "o"); 524 #endif 525 if (abs(openmen - op) > 7 + rnum(12)) 526 return (openmen > op); 527 #ifdef DEBUG 528 strcat(tests, "b"); 529 #endif 530 if (n) 531 return (n < 0); 532 #ifdef DEBUG 533 strcat(tests, "e"); 534 #endif 535 if (abs(endman - em) > rnum(2)) 536 return (endman > em); 537 #ifdef DEBUG 538 strcat(tests, "f"); 539 #endif 540 if (abs(frc - oldfrc) > rnum(2)) 541 return (frc < oldfrc); 542 #ifdef DEBUG 543 strcat(tests, "p"); 544 #endif 545 if (abs(n = pt - points) > rnum(4)) 546 return (n > 0); 547 #ifdef DEBUG 548 strcat(tests, "i"); 549 #endif 550 if (*inptr - menin) 551 return (*inptr > menin); 552 #ifdef DEBUG 553 strcat(tests, "f"); 554 #endif 555 if (abs(frp - oldfrp) > rnum(2)) 556 return (frp > oldfrp); 557 return (rnum(2)); 558 } 559 } 560