|
|
1.1 ! root 1: /* ! 2: * lines.c ! 3: * 4/2/87 ! 4: * Copyright (C) 1984-1987 by Stephen A. Ness. ! 5: * Lines of action, a game by Claude Soucie. ! 6: * Reference: Sid Sackson, "A Gamut of Games," Random House 1969, pp. 34-39. ! 7: */ ! 8: ! 9: /* ! 10: * This program maintains a lot of information about the current position ! 11: * to facilitate speedy generation and evaluation of possible next moves. ! 12: * Moving or unmoving a piece is rather complicated as a result. ! 13: * It also uses pointer arithmetic to do array calculations within loops. ! 14: * The number of positions generated is roughly k*((width+1)^(depth-1)), ! 15: * where k is the number of legal moves for a position (about 36 at start). ! 16: * Not all generated positions need to be evaluated, however. ! 17: * On an IBM PC, this program evaluates about 48 positions per second. ! 18: */ ! 19: ! 20: #include <stdio.h> ! 21: ! 22: #if COHERENT ! 23: #include <sys/timeb.h> ! 24: #endif ! 25: #if MSDOS ! 26: #include <timeb.h> ! 27: #define IBMPC 1 /* Use IBM PC graphic characters. */ ! 28: #endif ! 29: #ifdef DEBUG ! 30: #include <assert.h> ! 31: #endif ! 32: ! 33: /* General definitions. */ ! 34: #define VERSION "1.2" /* Version number. */ ! 35: #define DEPTH 3 /* Initial tree search depth. */ ! 36: #define WIDTH 25 /* Initial tree search width. */ ! 37: #define MAXWIDTH 96 /* Max number of next moves (12 * 8). */ ! 38: #define MAXDEPTH 5 /* Max move tree search depth. */ ! 39: #define NMOVES 200 /* Max number of moves in game. */ ! 40: #define EDGE -1 /* Edge marker for board. */ ! 41: #define WIN 32767 /* Value for winning position. */ ! 42: #define LOSS -32767 /* Value for losing position. */ ! 43: #define MAN(x) ((x)?MAN1:MAN0) /* Graphic character for x's men. */ ! 44: ! 45: /* Graphic characters for printable board. */ ! 46: #if IBMPC ! 47: #define SPACE 32 ! 48: #define VERT 179 ! 49: #define HORIZ 196 ! 50: #define TOPL 218 ! 51: #define TOPM 194 ! 52: #define TOPR 191 ! 53: #define MIDL 195 ! 54: #define MIDM 197 ! 55: #define MIDR 180 ! 56: #define BOTL 192 ! 57: #define BOTM 193 ! 58: #define BOTR 217 ! 59: #define MAN0 4 ! 60: #define MAN1 79 ! 61: #else ! 62: #define SPACE ' ' ! 63: #define VERT '|' ! 64: #define HORIZ '-' ! 65: #define TOPL '+' ! 66: #define TOPM '+' ! 67: #define TOPR '+' ! 68: #define MIDL '+' ! 69: #define MIDM '+' ! 70: #define MIDR '+' ! 71: #define BOTL '+' ! 72: #define BOTM '+' ! 73: #define BOTR '+' ! 74: #define MAN0 'X' ! 75: #define MAN1 'O' ! 76: #endif ! 77: ! 78: char *rules = "\ ! 79: Object: to get all of player's pieces into one connected group.\n\ ! 80: Horizontally, vertically or diagonally adjacent pieces are connected.\n\ ! 81: Movement: A piece may move horizontally, vertically or diagonally, but\n\ ! 82: it MUST move exactly the number of squares given by the total number\n\ ! 83: of pieces (friendly and enemy) in the row, column or diagonal of\n\ ! 84: movement. A piece may jump over friendly pieces, but it may not jump\n\ ! 85: over enemy pieces. A piece may land on an enemy piece, removing it\n\ ! 86: from the game, but it may not land on a friendly piece."; ! 87: ! 88: char *help = "\ ! 89: Commands:\n\ ! 90: \td3\tSet tree search depth to 3.\n\ ! 91: \te\tEvaluate current position.\n\ ! 92: \th\tPrint help information.\n\ ! 93: \ti\tInitialize new board.\n\ ! 94: \tl\tList game on console.\n\ ! 95: \tlfile\tList game to file.\n\ ! 96: \tm\tGenerate next move.\n\ ! 97: \tm1234\tMove from 12 to 34, then generate reply.\n\ ! 98: \tM1234\tMove from 12 to 34, do not generate reply.\n\ ! 99: \tp\tPrint the board.\n\ ! 100: \tq\tQuit.\n\ ! 101: \tr\tPrint rules.\n\ ! 102: \tu\tUndo most recent move.\n\ ! 103: \tv\tPrint move generation information.\n\ ! 104: \tw25\tSet tree search width to 25.\n\ ! 105: \txfile\tExecute moves from list file.\n\ ! 106: \t!cmd\tPass cmd to system for execution (COHERENT, MSDOS only).\n\ ! 107: A command must be followed by a <return>."; ! 108: ! 109: /* Structure to represent moves. */ ! 110: typedef struct move { ! 111: int m_val; /* Value. */ ! 112: char m_from; /* From. */ ! 113: char m_to; /* To. */ ! 114: char m_man; /* Man number. */ ! 115: char m_cap; /* Captured man number. */ ! 116: } MOVE; ! 117: ! 118: /* Globals. */ ! 119: int board[100]; /* Board with edges added. */ ! 120: int boarddist[100][100]; /* Distances between squares on board. */ ! 121: int cindex[100][4]; /* Indices into count for [pos][dir]. */ ! 122: char command[81]; /* Command. */ ! 123: int count[46]; /* Number of men in row, col, diagonal. */ ! 124: int depth = DEPTH; /* Search depth. */ ! 125: int firstman[2]; /* First man number for each player. */ ! 126: int group[25]; /* Grouping of men. */ ! 127: int lastman[2]; /* Last man number for each player. */ ! 128: int loc[25]; /* Locations of men. */ ! 129: int maxgen; /* Largest width of moves generated. */ ! 130: MOVE movelist[NMOVES]; /* Moves to date. */ ! 131: long neval; /* Number of positions evaluated. */ ! 132: MOVE nextmove[MAXDEPTH][MAXWIDTH]; /* Move generation tree. */ ! 133: long ngen; /* Number of moves generated. */ ! 134: int nmove; /* Move number. */ ! 135: int npos; /* Number of positions from which moves generated. */ ! 136: int offset[4]; /* Board offsets for moves. */ ! 137: int opp; /* Opponent. */ ! 138: char pboard[18][37]; /* Printable representation of board. */ ! 139: int plr; /* Player to move next. */ ! 140: int val[2]; /* Value of player's position. */ ! 141: int vflag = 0; /* Verbose flag. */ ! 142: int width = WIDTH; /* Search width. */ ! 143: ! 144: #if COHERENT || MSDOS ! 145: time_t start; /* Move starting time. */ ! 146: extern time_t time(); ! 147: #endif ! 148: ! 149: main() ! 150: { ! 151: register int flag, n; ! 152: MOVE m; ! 153: MOVE *mp = &m; ! 154: ! 155: staticinit(); ! 156: printf("Lines of Action V%s\n(c) 1984-1987 by Stephen A. Ness.\n", VERSION); ! 157: puts("Type 'h' followed by <return> if you need help."); ! 158: initialize(); ! 159: for (;;) { ! 160: printf("? "); ! 161: if (gets(command)==NULL) ! 162: exit(0); ! 163: switch(command[0]) { ! 164: case 'd': ! 165: setparam(&depth, "depth", MAXDEPTH); ! 166: break; ! 167: case 'e': ! 168: n = value(); ! 169: printf("board(%c)=%d board(%c)=%d value=%d\n", MAN0, val[0], MAN1, val[1], n); ! 170: break; ! 171: case 'h': ! 172: printf("%s\nPlayer %c moves next.\n", help, MAN(plr)); ! 173: break; ! 174: case 'i': ! 175: initialize(); ! 176: break; ! 177: case 'l': ! 178: listgame(); ! 179: break; ! 180: case 'm': ! 181: flag = 1; ! 182: if (command[1]=='\0') ! 183: goto reply; ! 184: goto moveit; ! 185: case 'M': ! 186: flag = 0; ! 187: moveit: if (legalmove(atoi(&command[1]),mp)) { ! 188: dodisp(mp, 0); ! 189: domove(mp); ! 190: if (gameover()) ! 191: break; ! 192: } ! 193: else { ! 194: puts("Illegal move -- try again"); ! 195: break; ! 196: } ! 197: if (flag) ! 198: printboard(); ! 199: reply: if (flag) { ! 200: if (vflag) { ! 201: #if COHERENT || MSDOS ! 202: start = time(NULL); ! 203: #endif ! 204: ngen = neval = 0L; ! 205: npos = maxgen = 0; ! 206: } ! 207: findbest(mp, depth, LOSS); ! 208: if (mp->m_man == 0) { /* Stalemate */ ! 209: puts("Game drawn by stalemate."); ! 210: puts("Type i to play again or q to quit."); ! 211: break; ! 212: } ! 213: if (vflag) { ! 214: #if COHERENT || MSDOS ! 215: printf("Elapsed time %ld seconds.\n", time(NULL)-start); ! 216: #endif ! 217: printf("Generated %ld moves from %d positions.\nEvaluated %ld positions.\nMaximum width %d.\n", ngen, npos, neval, maxgen); ! 218: } ! 219: printf("%c moves %d%c%d.\n", MAN(plr), mp->m_from, (mp->m_cap)?'*':'-', mp->m_to); ! 220: dodisp(mp, 0); ! 221: domove(mp); ! 222: if (gameover()) ! 223: break; ! 224: } ! 225: printboard(); ! 226: break; ! 227: case 'p': ! 228: printboard(); ! 229: break; ! 230: case 'q': ! 231: exit(0); ! 232: break; ! 233: case 'r': ! 234: puts(rules); ! 235: break; ! 236: case 'u': ! 237: domove(NULL); ! 238: dodisp(&movelist[nmove], 1); ! 239: printboard(); ! 240: break; ! 241: case 'v': ! 242: vflag = 1; ! 243: break; ! 244: case 'w': ! 245: setparam(&width, "width", MAXWIDTH); ! 246: break; ! 247: case 'x': ! 248: execfile(); ! 249: break; ! 250: #if COHERENT || MSDOS ! 251: case '!': ! 252: system(&command[1]); ! 253: break; ! 254: #endif ! 255: default: ! 256: puts("Command not recognized -- try again."); ! 257: puts("Type h<return> if you need help."); ! 258: break; ! 259: } ! 260: } ! 261: } ! 262: ! 263: /* Compare next moves. Called indirectly by qsort. */ ! 264: compnext(p1, p2) char *p1, *p2; ! 265: { ! 266: register int val1, val2; ! 267: ! 268: val1 = ((MOVE *)p1)->m_val; ! 269: val2 = ((MOVE *)p2)->m_val; ! 270: return ((val1 < val2) ? -1 : ((val1 == val2) ? 0 : 1)); ! 271: } ! 272: ! 273: /* Display character c at pos on printable board. */ ! 274: display(c,pos) ! 275: { ! 276: pboard[2*(pos/10)-1][4*(pos%10)-2] = c; ! 277: } ! 278: ! 279: /* Update printable display for move *mp. */ ! 280: /* Separated from domove() for speed. */ ! 281: dodisp(mp, undo) register MOVE *mp; int undo; ! 282: { ! 283: if (undo) { /* Undo move */ ! 284: display(SPACE, mp->m_to); ! 285: display(MAN(plr), mp->m_from); ! 286: if (mp->m_cap) ! 287: display(MAN(opp), mp->m_to); ! 288: } ! 289: else { ! 290: display(SPACE, mp->m_from); ! 291: display(MAN(plr), mp->m_to); ! 292: } ! 293: } ! 294: ! 295: /* Combine adjacent pieces into groups. */ ! 296: dogroup(n) int n; ! 297: { ! 298: int i, j, first, last, man, mgroup, igroup; ! 299: register k; ! 300: register int *gp; ! 301: int *bp, *offp, *gfp; ! 302: ! 303: first = firstman[n]; ! 304: last = lastman[n]; ! 305: gp = gfp = &group[first]; ! 306: for (k=first; k<=last; k++) ! 307: *gp++ = k; /* Put man i in group i initially */ ! 308: for (i=first; i<=last; i++) { ! 309: bp = &board[loc[i]]; ! 310: offp = &offset[0]; ! 311: igroup = group[i]; /* Note that i<>group[i] sometimes */ ! 312: for (j=0; j<4; j++) { ! 313: man = *(bp+*offp++); /* Occupant of adjacent square */ ! 314: if ((first<=man)&&(man<=last)&&(group[man]!=igroup)) { ! 315: /* Join group[man] to group[i] */ ! 316: mgroup = group[man]; ! 317: gp = gfp; ! 318: for (k=first; k<=last; k++) { ! 319: if (*gp==mgroup) ! 320: *gp = igroup; ! 321: gp++; ! 322: } ! 323: } ! 324: } ! 325: } ! 326: } ! 327: ! 328: /* Make a legal move. */ ! 329: /* Does an unmove if mp is NULL. */ ! 330: /* Note that unmove is opp moving rather than plr. */ ! 331: /* The printable display is not updated. */ ! 332: domove(mp) ! 333: register MOVE *mp; ! 334: { ! 335: int i, from, to, man, cap, last, uflag; ! 336: register int *cifp, *citp; ! 337: ! 338: if (mp==NULL) { /* Unmove */ ! 339: if (nmove == 0) { ! 340: puts("Cannot unmove."); ! 341: return; ! 342: } ! 343: uflag = 1; ! 344: mp = &movelist[--nmove]; ! 345: from = mp->m_to; ! 346: to = mp->m_from; ! 347: val[opp] = -1; /* Value of opp's position changes */ ! 348: } ! 349: else { /* Normal move */ ! 350: if (nmove >= NMOVES) { ! 351: puts("Out of space on move list"); ! 352: exit(1); ! 353: } ! 354: uflag = 0; ! 355: movelist[nmove++] = *mp; /* Structure assignment */ ! 356: from = mp->m_from; ! 357: to = mp->m_to; ! 358: val[plr] = -1; /* Value of plr's position changes */ ! 359: } ! 360: man = mp->m_man; ! 361: cap = mp->m_cap; ! 362: #if DEBUG ! 363: printf("%smove %d from=%d to=%d cap=%d\n", (uflag)?"un":"", man, from, to, cap); ! 364: #endif ! 365: board[from] = 0; /* Vacate from location */ ! 366: if (cap) { /* Capture */ ! 367: if (uflag) { /* Rename cap as last, resurrect cap */ ! 368: val[plr] = -1; /* Value of plr's position changes */ ! 369: last = ++lastman[plr]; ! 370: i = loc[last] = loc[cap]; ! 371: board[i] = last; ! 372: cifp = &cindex[from][0]; ! 373: for (i=0; i<4; i++) ! 374: ++count[*cifp++]; ! 375: i = from; ! 376: } ! 377: else { /* Rename last man as cap */ ! 378: val[opp] = -1; /* Value of opp's position changes */ ! 379: citp = &cindex[to][0]; ! 380: for (i=0; i<4; i++) ! 381: --count[*citp++]; ! 382: i = loc[lastman[opp]--]; ! 383: } ! 384: board[i] = cap; ! 385: loc[cap] = i; ! 386: } ! 387: board[to] = man; /* Occupy to location */ ! 388: loc[man] = to; ! 389: cifp = &cindex[from][0]; ! 390: citp = &cindex[to][0]; ! 391: for (i=0; i<4; i++) { /* Adjust counts at from and to */ ! 392: --count[*cifp++]; ! 393: ++count[*citp++]; ! 394: } ! 395: opp = plr; ! 396: plr = 1 - plr; ! 397: } ! 398: ! 399: /* Evaluate position of player n and return its value. */ ! 400: /* The value is the sum of the distances between players not in same group. */ ! 401: eval(n) int n; ! 402: { ! 403: register int value; ! 404: register int *jp; ! 405: int i, j, first, last, igroup; ! 406: int *ip, *bdp, *gp, *gfp; ! 407: dogroup(n); /* Find groups of men */ ! 408: value = 0; ! 409: first = firstman[n]; ! 410: last = lastman[n]; ! 411: gfp = &group[first]; ! 412: ip = &loc[first]; ! 413: for (i=first; i<last; i++) { /* Man number i */ ! 414: #if DEBUG ! 415: assert(ip==&loc[i]); ! 416: assert(gfp==&group[i]); ! 417: #endif ! 418: igroup = *gfp++; /* igroup = group[i] */ ! 419: bdp = &boarddist[*ip++][0]; /* &boarddist[ipos][0] */ ! 420: gp = gfp; ! 421: jp = ip; ! 422: for (j=i+1; j<=last; j++) { /* Man number j */ ! 423: #if DEBUG ! 424: assert(gp==&group[j]); ! 425: assert(jp==&loc[j]); ! 426: #endif ! 427: if (*gp++ == igroup) /* group[j] == group[i] */ ! 428: jp++; ! 429: else ! 430: value += *(bdp+(*jp++)); /* boarddist[ipos][jpos] */ ! 431: } ! 432: } ! 433: return(value); ! 434: } ! 435: ! 436: /* Execute moves from list file. */ ! 437: execfile() ! 438: { ! 439: char *filename; ! 440: FILE *fp; ! 441: int count, from0, to0, from1, to1, eflag; ! 442: MOVE m; ! 443: register MOVE *mp; ! 444: ! 445: filename = &command[1]; ! 446: fp = fopen(filename, "r"); ! 447: if (fp == NULL) { ! 448: printf("Cannot open list file \"%s\"\n", filename); ! 449: return; ! 450: } ! 451: mp = &m; ! 452: eflag = 1; ! 453: while ((count = fscanf(fp, "%*d.%d%*c%d%d%*c%d", &from0, &to0, &from1, &to1)) != EOF) { ! 454: if ((count != 2) && (count != 4)) ! 455: goto done; ! 456: if (legalmove(100*from0+to0, mp)) { ! 457: dodisp(mp, 0); ! 458: domove(mp); ! 459: } ! 460: else ! 461: goto done; ! 462: if (count == 4) { ! 463: if (legalmove(100*from1+to1, mp)) { ! 464: dodisp(mp, 0); ! 465: domove(mp); ! 466: } ! 467: else ! 468: goto done; ! 469: } ! 470: } ! 471: eflag = 0; ! 472: done: ! 473: printboard(); ! 474: if (eflag) ! 475: puts("Bad list file"); ! 476: if (fclose(fp) == EOF) ! 477: printf("Cannot close list file \"%s\"\n", filename); ! 478: } ! 479: ! 480: /* Recursively find best move, searching to max depth d. */ ! 481: /* Store the move through mp (if non-NULL) and return its value. */ ! 482: /* Value less than limit means better move already known at previous level. */ ! 483: /* Value after move is from opp's point of view, hence lowest best for plr. */ ! 484: findbest(mp, d, limit) MOVE *mp; int d, limit; ! 485: { ! 486: register int n; ! 487: register MOVE *np; ! 488: int i, bestn, count; ! 489: MOVE *nextp, *bestnp; ! 490: ! 491: nextp = &nextmove[d-1][0]; ! 492: count = genmoves(nextp); ! 493: #if DEBUG ! 494: printf("findbest(%d) count=%d limit=%d:\n", d, count, limit); ! 495: #endif ! 496: if (count == 0) { /* Stalemate -- draw or loss? */ ! 497: if (mp) ! 498: mp->m_man = 0; /* To indicate stalemate */ ! 499: return(0); /* Let's call it a draw for now... */ ! 500: } ! 501: /* Find static values of next moves. */ ! 502: /* Needed for d>1 to determine WIN or LOSS positions. */ ! 503: bestnp = np = nextp; ! 504: bestn = WIN; ! 505: for (i=0; i<count; i++) { ! 506: domove(np); /* Try a move */ ! 507: np->m_val = n = value(); /* Evaluate position */ ! 508: #if DEBUG ! 509: printf("\tfrom=%d to=%d val=%d\n", np->m_from, np->m_to, n); ! 510: #endif ! 511: domove(NULL); /* And undo it */ ! 512: if (n < bestn) { ! 513: bestn = n; ! 514: bestnp = np; ! 515: if ((n == LOSS) || ((n <= limit) && (d == 1))) ! 516: goto out; /* Look no further */ ! 517: } ! 518: np++; ! 519: } ! 520: if (d > 1) { ! 521: /* If too wide, find best to look at. */ ! 522: if (count > width) { ! 523: qsort((char *)nextp, count, sizeof(MOVE), compnext); ! 524: count = width; ! 525: } ! 526: /* Find values of next moves recursively. */ ! 527: d--; /* Depth for next level */ ! 528: bestnp = np = nextp; ! 529: bestn = WIN; ! 530: for (i=0; i<count; i++) { ! 531: if (np->m_val != WIN) { ! 532: domove(np); ! 533: n = -findbest(NULL, d, -bestn); ! 534: #if DEBUG ! 535: printf("\tfrom=%d to=%d val=%d\n", np->m_from, np->m_to, n); ! 536: #endif ! 537: domove(NULL); /* And undo it */ ! 538: if (n < bestn) { ! 539: bestn = n; ! 540: bestnp = np; ! 541: if (n <= limit) ! 542: goto out; /* Look no further */ ! 543: } ! 544: } ! 545: np++; ! 546: } ! 547: } ! 548: out: ! 549: if (mp != NULL) ! 550: *mp = *bestnp; /* Structure assignment */ ! 551: #if DEBUG ! 552: printf("BEST: from=%d to=%d val=%d\n", bestnp->m_from, bestnp->m_to, bestnp->m_val); ! 553: #endif ! 554: return(bestn); ! 555: } ! 556: ! 557: /* Test for winning or losing position. */ ! 558: gameover() ! 559: { ! 560: value(); ! 561: if ((val[0] != 0) && (val[1] != 0)) ! 562: return(0); ! 563: printboard(); ! 564: if ((val[0] == 0) && (val[1] == 0)) ! 565: puts("Drawn game."); ! 566: else ! 567: printf("Player %c wins.\n", MAN(val[0])); ! 568: puts("Type i to play again or q to quit."); ! 569: return(1); ! 570: } ! 571: ! 572: /* Generate all legal moves from current position, return count. */ ! 573: genmoves(mp) MOVE *mp; ! 574: { ! 575: register int off; ! 576: register int *bp; ! 577: int i, j, k, first, last, ofirst, olast, pos, d, dir, toff, nmoves; ! 578: int *locp, *cip; ! 579: ! 580: first = firstman[plr]; ! 581: last = lastman[plr]; ! 582: ofirst = firstman[opp]; ! 583: olast = lastman[opp]; ! 584: nmoves = 0; /* Moves generated */ ! 585: locp = &loc[first]; /* loc pointer */ ! 586: for (i=first; i<=last; i++) { /* Player's man i */ ! 587: #if DEBUG ! 588: assert(locp==&loc[i]); ! 589: printf("Gen player=%d man=%d loc=%d\n", plr, i, *locp); ! 590: #endif ! 591: pos = *locp++; /* Position of i */ ! 592: cip = &cindex[pos][0]; ! 593: for (j=0; j<4; j++) { /* Direction of movement */ ! 594: d = count[*cip++]; /* Distance */ ! 595: off = offset[j]; /* Offset in given direction */ ! 596: toff = d * off; /* Total offset to target */ ! 597: dir = 0; ! 598: again: ! 599: #if DEBUG ! 600: printf("\tdir=%d dist=%d off=%d ", j+4*dir, d, off); ! 601: #endif ! 602: bp = &board[pos]; /* Ptr to pos */ ! 603: for (k=1; k<d; k++) { ! 604: bp += off; /* Next position */ ! 605: if ((*bp==EDGE) || ((*bp>=ofirst)&&(*bp<=olast))) ! 606: goto reject; /* Edge or occupied by opp */ ! 607: } ! 608: bp += off; /* Ptr to target position */ ! 609: if ((*bp==EDGE) || ((*bp>=first)&&(*bp<=last))) ! 610: goto reject; /* Edge or occupied by plr */ ! 611: /* Found legal move */ ! 612: nmoves++; ! 613: mp->m_from = pos; ! 614: mp->m_to = pos + toff; ! 615: mp->m_man = i; ! 616: mp->m_cap = *bp; ! 617: mp++; ! 618: #if DEBUG ! 619: printf("legal move to=%d cap=%d", pos+toff, *bp); ! 620: #endif ! 621: reject: ! 622: #if DEBUG ! 623: putchar('\n'); ! 624: #endif ! 625: if (dir == 0) { /* Try opposite direction */ ! 626: dir++; ! 627: off = -off; ! 628: toff = -toff; ! 629: goto again; ! 630: } ! 631: } ! 632: } ! 633: #if DEBUG ! 634: printf("genmoves returning %d moves\n", nmoves); ! 635: #endif ! 636: if (vflag) { ! 637: npos++; ! 638: ngen += ((long)nmoves); ! 639: if (nmoves > maxgen) ! 640: maxgen = nmoves; ! 641: } ! 642: return(nmoves); ! 643: } ! 644: ! 645: /* Initialize everything. */ ! 646: initialize() ! 647: { ! 648: register char *cp; ! 649: register int j; ! 650: int i, n; ! 651: int *ip; ! 652: ! 653: /* Globals. */ ! 654: ip = &board[0]; ! 655: for (i=0; i<100; i++) ! 656: *ip++ = ((i%10==0)||(i%10==9)||(i/10==0)||(i/10==9))?EDGE:0; ! 657: plr = nmove = 0; ! 658: opp = 1; ! 659: val[0] = val[1] = -1; ! 660: firstman[0] = 1; ! 661: lastman[0] = 12; ! 662: firstman[1] = 13; ! 663: lastman[1] = 24; ! 664: for (j=0; j<46; j++) ! 665: count[j] = 2; ! 666: count[0] = count[7] = count[8] = count[15] = 6; ! 667: count[16] = count[23] = count[30] = count[31] = count[38] = count[45] = 0; ! 668: ! 669: /* Initialize the printable display. */ ! 670: cp = &pboard[0][0]; ! 671: for (i=0; i<17; i++) { ! 672: for (j=0; j<33; j++) ! 673: *cp++ = ((i%2) ! 674: ? ((j%4)?SPACE:VERT) ! 675: : ! 676: ((j%4) ! 677: ? HORIZ ! 678: : ! 679: ((i==0) ! 680: ? ((j==0)?TOPL:((j==32)?TOPR:TOPM)) ! 681: : ! 682: ((i==16) ! 683: ? ((j==0)?BOTL:((j==32)?BOTR:BOTM)) ! 684: : ((j==0)?MIDL:((j==32)?MIDR:MIDM)) ! 685: )))); ! 686: *cp++ = SPACE; ! 687: *cp++ = ((i%2) ? '1' + i/2 : SPACE); ! 688: *cp++ = ((i%2) ? '0' : SPACE); ! 689: *cp++ = '\n'; ! 690: } ! 691: for (j=1; j<=8; j++) { ! 692: *cp++ = SPACE; ! 693: *cp++ = SPACE; ! 694: *cp++ = '0' + j; ! 695: *cp++ = SPACE; ! 696: } ! 697: *cp++ = '\0'; ! 698: ! 699: /* Initial positions. */ ! 700: n = 1; /* Man number */ ! 701: for (i=12; i<=17; i++) { ! 702: display (MAN0, i); ! 703: loc[n] = i; ! 704: board[i] = n++; ! 705: } ! 706: for (i=82; i<=87; i++) { ! 707: display (MAN0, i); ! 708: loc[n] = i; ! 709: board[i] = n++; ! 710: } ! 711: for (i=21; i<=71; i+=10) { ! 712: display (MAN1, i); ! 713: loc[n] = i; ! 714: board[i] = n++; ! 715: } ! 716: for (i=28; i<=78; i+=10) { ! 717: display (MAN1, i); ! 718: loc[n] = i; ! 719: board[i] = n++; ! 720: } ! 721: ! 722: printf("%c moves first.\n", MAN0); ! 723: printboard(); ! 724: } ! 725: ! 726: /* Test whether n is legal move and fill in *mp accordingly. */ ! 727: legalmove(n,mp) int n; MOVE *mp; ! 728: { ! 729: register int *bp; ! 730: register int i; ! 731: int from, to, fromx, fromy, tox, toy, dir, off, dist; ! 732: ! 733: mp->m_from = from = n/100; ! 734: mp->m_to = to = n%100; ! 735: mp->m_man = board[from]; ! 736: if ((board[from]<firstman[plr]) || (board[from]>lastman[plr])) ! 737: return(0); ! 738: mp->m_cap = board[to]; ! 739: fromx = from/10; ! 740: fromy = from%10; ! 741: tox = to/10; ! 742: toy = to%10; ! 743: if (fromx==tox) dir = 0; ! 744: else if (fromy==toy) dir = 1; ! 745: else if (fromx+fromy==tox+toy) dir = 2; ! 746: else if (fromx-fromy==tox-toy) dir = 3; ! 747: else return(0); ! 748: off = offset[dir]; ! 749: if (from>to) ! 750: off = -off; ! 751: dist = count[cindex[from][dir]]; ! 752: bp = &board[from]; ! 753: for (i=1; i<dist; i++) { ! 754: bp += off; ! 755: if ((*bp==EDGE)||((*bp>=firstman[opp])&&(*bp<=lastman[opp]))) ! 756: return(0); ! 757: } ! 758: bp += off; ! 759: if ((*bp==EDGE)||((*bp>=firstman[plr])&&(*bp<=lastman[plr]))||(bp!=&board[to])) ! 760: return(0); ! 761: return(1); ! 762: } ! 763: ! 764: /* List game. */ ! 765: listgame() ! 766: { ! 767: register MOVE *mp; ! 768: register int i; ! 769: char c; ! 770: FILE *fp = stdout; ! 771: char *filename = &command[1]; ! 772: ! 773: if (*filename) { ! 774: fp = fopen(filename, "w"); ! 775: if (fp == NULL) { ! 776: printf("Cannot open list file \"%s\"\n", filename); ! 777: return; ! 778: } ! 779: } ! 780: mp = &movelist[0]; ! 781: for (i=0; i<nmove; i++) { ! 782: if (i%2 == 0) ! 783: fprintf(fp, "\n%d. ", i/2+1); ! 784: c = (mp->m_cap) ? '*' : '-'; ! 785: fprintf(fp, "%d%c%d ", mp->m_from, c, mp->m_to); ! 786: mp++; ! 787: } ! 788: putc('\n', fp); ! 789: if ((fp != stdout) && (fclose(fp) == EOF)) ! 790: printf("Cannot close list file \"%s\"\n", filename); ! 791: } ! 792: ! 793: /* Print the board. */ ! 794: printboard() ! 795: { ! 796: puts(pboard); ! 797: } ! 798: ! 799: /* Set parameter (depth or width). */ ! 800: setparam(sp, s, max) int *sp; char *s; int max; ! 801: { ! 802: register int i; ! 803: ! 804: printf("Old search %s is %d.\n", s, *sp); ! 805: if (command[1]=='\0') ! 806: return; ! 807: i = atoi(&command[1]); ! 808: if (i < 1 || i > max) { ! 809: printf("%s arg must be between 1 and %d -- try again.\n", s, max); ! 810: return; ! 811: } ! 812: *sp = i; ! 813: printf("New search %s is %d.\n", s, *sp); ! 814: } ! 815: ! 816: /* Initialize readonly global data. */ ! 817: staticinit() ! 818: { ! 819: register int *ip; ! 820: register int j; ! 821: int i, ix, iy, dx, dy, n; ! 822: ! 823: offset[0] = 1; ! 824: offset[1] = 10; ! 825: offset[2] = 9; ! 826: offset[3] = 11; ! 827: ip = &boarddist[0][0]; ! 828: for (i=0; i<100; i++) { ! 829: ix = i/10; ! 830: iy = i%10; ! 831: for (j=0; j<100; j++) { ! 832: dx = ix - j/10; /* x distance i to j */ ! 833: dy = iy - j%10; /* y distance i to j */ ! 834: if (dx < 0) ! 835: dx = -dx; ! 836: if (dy < 0) ! 837: dy = -dy; ! 838: if (dx < dy) ! 839: dx = dy; ! 840: *ip++ = --dx; ! 841: } ! 842: } ! 843: for (i=0; i<8; i++) ! 844: for (j=0; j<8; j++) { ! 845: n = 10*(i+1) + j+1; ! 846: cindex[n][0] = i; ! 847: cindex[n][1] = 8+j; ! 848: cindex[n][2] = 16 + i + j; ! 849: cindex[n][3] = 38 + i - j; ! 850: } ! 851: } ! 852: ! 853: /* Return value of current position. */ ! 854: /* Reevaluate a position only if it has changed. */ ! 855: value() ! 856: { ! 857: register int pval, oval; ! 858: ! 859: neval++; ! 860: pval = val[plr]; ! 861: oval = val[opp]; ! 862: if (pval < 0) ! 863: pval = val[plr] = eval(plr); ! 864: if (oval < 0) ! 865: oval = val[opp] = eval(opp); ! 866: if (pval == 0) ! 867: return((oval) ? WIN : 0); ! 868: return((oval) ? oval-pval : LOSS); ! 869: } ! 870: ! 871: /* end of lines.c */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.