Annotation of coherent/d/usr/games/lines.c, revision 1.1

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 */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.