official-stockfish / Stockfish

A free and strong UCI chess engine
https://stockfishchess.org/
GNU General Public License v3.0
11.26k stars 2.24k forks source link

Skill Level Weird Bestmove Issue #2217

Closed xigua closed 5 years ago

xigua commented 5 years ago

I am testing a very straight forward mate in one puzzle 7R/2r2pk1/p5p1/1pp3P1/8/P6R/1PP5/2K5 w - - 0 3

And try to use different skill level of stockfish 10 to solve the puzzle but got some very strange result.

I am using the following commands setoption name Skill Level value 1 ucinewgame position fen '7R/2r2pk1/p5p1/1pp3P1/8/P6R/1PP5/2K5 w - - 0 3' go depth 10

It will return the following info depth 1 seldepth 1 multipv 1 score mate 1 nodes 141 nps 141000 tbhits 0 time 1 pv h3h7 info depth 2 seldepth 2 multipv 1 score mate 1 nodes 405 nps 405000 tbhits 0 time 1 pv h3h7 info depth 3 seldepth 2 multipv 1 score mate 1 nodes 597 nps 597000 tbhits 0 time 1 pv h3h7 info depth 4 seldepth 2 multipv 1 score mate 1 nodes 775 nps 387500 tbhits 0 time 2 pv h3h7 info depth 5 seldepth 2 multipv 1 score mate 1 nodes 952 nps 476000 tbhits 0 time 2 pv h3h7 info depth 6 seldepth 2 multipv 1 score mate 1 nodes 1133 nps 566500 tbhits 0 time 2 pv h3h7 info depth 7 seldepth 2 multipv 1 score mate 1 nodes 1318 nps 659000 tbhits 0 time 2 pv h3h7 info depth 8 seldepth 2 multipv 1 score mate 1 nodes 1507 nps 753500 tbhits 0 time 2 pv h3h7 info depth 9 seldepth 2 multipv 1 score mate 1 nodes 1702 nps 851000 tbhits 0 time 2 pv h3h7 info depth 10 seldepth 2 multipv 1 score mate 1 nodes 1900 nps 950000 tbhits 0 time 2 pv h3h7 bestmove b2b3 ponder c7d7

The first discovery is bestmove "b2b3" doesn't match with pv in all 10 depth "h3h7". If we can explain that bestmove is adjusted due to the skill level setting and skill level = 1 is not very strong (although it's just a mate in one puzzle). Then I tried different skill level, I found when skill level = 20, it's consistently having correct bestmove "h3h7" however, even with skill level=18, I am still getting incorrect bestmove: setoption name Skill Level value 18 go depth 10 info depth 1 seldepth 2 multipv 1 score mate 1 nodes 122 nps 61000 tbhits 0 time 2 pv h3h7 info depth 2 seldepth 2 multipv 1 score mate 1 nodes 283 nps 141500 tbhits 0 time 2 pv h3h7 info depth 3 seldepth 2 multipv 1 score mate 1 nodes 438 nps 219000 tbhits 0 time 2 pv h3h7 info depth 4 seldepth 2 multipv 1 score mate 1 nodes 593 nps 296500 tbhits 0 time 2 pv h3h7 info depth 5 seldepth 2 multipv 1 score mate 1 nodes 748 nps 374000 tbhits 0 time 2 pv h3h7 info depth 6 seldepth 2 multipv 1 score mate 1 nodes 903 nps 451500 tbhits 0 time 2 pv h3h7 info depth 7 seldepth 2 multipv 1 score mate 1 nodes 1058 nps 529000 tbhits 0 time 2 pv h3h7 info depth 8 seldepth 2 multipv 1 score mate 1 nodes 1213 nps 606500 tbhits 0 time 2 pv h3h7 info depth 9 seldepth 2 multipv 1 score mate 1 nodes 1368 nps 684000 tbhits 0 time 2 pv h3h7 info depth 10 seldepth 2 multipv 1 score mate 1 nodes 1526 nps 763000 tbhits 0 time 2 pv h3h7 bestmove h3h7 go depth 10 info depth 1 seldepth 2 multipv 1 score mate 1 nodes 122 nps 61000 tbhits 0 time 2 pv h3h7 info depth 2 seldepth 2 multipv 1 score mate 1 nodes 283 nps 141500 tbhits 0 time 2 pv h3h7 info depth 3 seldepth 2 multipv 1 score mate 1 nodes 438 nps 219000 tbhits 0 time 2 pv h3h7 info depth 4 seldepth 2 multipv 1 score mate 1 nodes 593 nps 296500 tbhits 0 time 2 pv h3h7 info depth 5 seldepth 2 multipv 1 score mate 1 nodes 748 nps 374000 tbhits 0 time 2 pv h3h7 info depth 6 seldepth 2 multipv 1 score mate 1 nodes 903 nps 451500 tbhits 0 time 2 pv h3h7 info depth 7 seldepth 2 multipv 1 score mate 1 nodes 1058 nps 529000 tbhits 0 time 2 pv h3h7 info depth 8 seldepth 2 multipv 1 score mate 1 nodes 1213 nps 606500 tbhits 0 time 2 pv h3h7 info depth 9 seldepth 2 multipv 1 score mate 1 nodes 1368 nps 684000 tbhits 0 time 2 pv h3h7 info depth 10 seldepth 2 multipv 1 score mate 1 nodes 1526 nps 763000 tbhits 0 time 2 pv h3h7 bestmove h3h7 go depth 10 info depth 1 seldepth 2 multipv 1 score mate 1 nodes 122 nps 122000 tbhits 0 time 1 pv h3h7 info depth 2 seldepth 2 multipv 1 score mate 1 nodes 283 nps 283000 tbhits 0 time 1 pv h3h7 info depth 3 seldepth 2 multipv 1 score mate 1 nodes 438 nps 438000 tbhits 0 time 1 pv h3h7 info depth 4 seldepth 2 multipv 1 score mate 1 nodes 593 nps 593000 tbhits 0 time 1 pv h3h7 info depth 5 seldepth 2 multipv 1 score mate 1 nodes 748 nps 748000 tbhits 0 time 1 pv h3h7 info depth 6 seldepth 2 multipv 1 score mate 1 nodes 903 nps 903000 tbhits 0 time 1 pv h3h7 info depth 7 seldepth 2 multipv 1 score mate 1 nodes 1058 nps 1058000 tbhits 0 time 1 pv h3h7 info depth 8 seldepth 2 multipv 1 score mate 1 nodes 1213 nps 1213000 tbhits 0 time 1 pv h3h7 info depth 9 seldepth 2 multipv 1 score mate 1 nodes 1368 nps 1368000 tbhits 0 time 1 pv h3h7 info depth 10 seldepth 2 multipv 1 score mate 1 nodes 1526 nps 1526000 tbhits 0 time 1 pv h3h7 bestmove a3a4 ponder b5a4 go depth 10 info depth 1 seldepth 2 multipv 1 score mate 1 nodes 122 nps 122000 tbhits 0 time 1 pv h3h7 info depth 2 seldepth 2 multipv 1 score mate 1 nodes 283 nps 141500 tbhits 0 time 2 pv h3h7 info depth 3 seldepth 2 multipv 1 score mate 1 nodes 438 nps 219000 tbhits 0 time 2 pv h3h7 info depth 4 seldepth 2 multipv 1 score mate 1 nodes 593 nps 296500 tbhits 0 time 2 pv h3h7 info depth 5 seldepth 2 multipv 1 score mate 1 nodes 748 nps 374000 tbhits 0 time 2 pv h3h7 info depth 6 seldepth 2 multipv 1 score mate 1 nodes 903 nps 451500 tbhits 0 time 2 pv h3h7 info depth 7 seldepth 2 multipv 1 score mate 1 nodes 1058 nps 529000 tbhits 0 time 2 pv h3h7 info depth 8 seldepth 2 multipv 1 score mate 1 nodes 1213 nps 606500 tbhits 0 time 2 pv h3h7 info depth 9 seldepth 2 multipv 1 score mate 1 nodes 1368 nps 684000 tbhits 0 time 2 pv h3h7 info depth 10 seldepth 2 multipv 1 score mate 1 nodes 1526 nps 763000 tbhits 0 time 2 pv h3h7 bestmove a3a4 ponder b5a4 go depth 10 info depth 1 seldepth 2 multipv 1 score mate 1 nodes 122 nps 61000 tbhits 0 time 2 pv h3h7 info depth 2 seldepth 2 multipv 1 score mate 1 nodes 283 nps 141500 tbhits 0 time 2 pv h3h7 info depth 3 seldepth 2 multipv 1 score mate 1 nodes 438 nps 219000 tbhits 0 time 2 pv h3h7 info depth 4 seldepth 2 multipv 1 score mate 1 nodes 593 nps 296500 tbhits 0 time 2 pv h3h7 info depth 5 seldepth 2 multipv 1 score mate 1 nodes 748 nps 374000 tbhits 0 time 2 pv h3h7 info depth 6 seldepth 2 multipv 1 score mate 1 nodes 903 nps 451500 tbhits 0 time 2 pv h3h7 info depth 7 seldepth 2 multipv 1 score mate 1 nodes 1058 nps 529000 tbhits 0 time 2 pv h3h7 info depth 8 seldepth 2 multipv 1 score mate 1 nodes 1213 nps 606500 tbhits 0 time 2 pv h3h7 info depth 9 seldepth 2 multipv 1 score mate 1 nodes 1368 nps 684000 tbhits 0 time 2 pv h3h7 info depth 10 seldepth 2 multipv 1 score mate 1 nodes 1526 nps 763000 tbhits 0 time 2 pv h3h7 bestmove c2c3 ponder c7d7 go depth 10 info depth 1 seldepth 2 multipv 1 score mate 1 nodes 122 nps 122000 tbhits 0 time 1 pv h3h7 info depth 2 seldepth 2 multipv 1 score mate 1 nodes 283 nps 283000 tbhits 0 time 1 pv h3h7 info depth 3 seldepth 2 multipv 1 score mate 1 nodes 438 nps 438000 tbhits 0 time 1 pv h3h7 info depth 4 seldepth 2 multipv 1 score mate 1 nodes 593 nps 593000 tbhits 0 time 1 pv h3h7 info depth 5 seldepth 2 multipv 1 score mate 1 nodes 748 nps 748000 tbhits 0 time 1 pv h3h7 info depth 6 seldepth 2 multipv 1 score mate 1 nodes 903 nps 903000 tbhits 0 time 1 pv h3h7 info depth 7 seldepth 2 multipv 1 score mate 1 nodes 1058 nps 1058000 tbhits 0 time 1 pv h3h7 info depth 8 seldepth 2 multipv 1 score mate 1 nodes 1213 nps 1213000 tbhits 0 time 1 pv h3h7 info depth 9 seldepth 2 multipv 1 score mate 1 nodes 1368 nps 684000 tbhits 0 time 2 pv h3h7 info depth 10 seldepth 2 multipv 1 score mate 1 nodes 1526 nps 763000 tbhits 0 time 2 pv h3h7 bestmove c2c3 ponder c7d7

interesting thing is, I ran the same command "go depth 10" 6 times, and I got 3 different bestmoves although infos were very consistent at h3h7.

Did I understand it wrong? To my understanding, skill level 18 should not do wrong in this simple mate in one puzzle.

Thanks a lot.

creatorkuang commented 5 years ago

I'm confused, too. Anyone know why?

gvreuls commented 5 years ago

This is how it's supposed to be. If you set a skill level the engine picks a sub par move at random. Edit: the skill level determines how bad the moves that get on the list the engine picks from are.

MichaelB7 commented 5 years ago

Not a good test position for skill level usage since there are at least 10 moves that are mate-in-2 , the value between mate in 2 and mate in 1 is small. So although the randomness for level 18 is small, it's big enough to switch the move to a longer mate. So, yes skill levels would clearly impact mate problems , especially when the DTM difference is just one move. Skill level is designed for human play and not mate problems, but i'm sure you know that and you were just curious to see the impact.

xigua commented 5 years ago

Understood now. But then what the information about 'pv' in each info means? Is it the best option that the skill level can come up with given the thinking depth? Can we use pv as 'real bestmove' instead?

Another question, how can we mimic a human player with ELO=600 (for example) using stockfish?

Really appreciate the help and enlightening.

joergoster commented 5 years ago

@xigua You're still getting incorrect moves even at Skill Level 18 because you didn't issue a 'ucinewgame' command after changing the setting.

joergoster commented 5 years ago

What really seems to be missing is the output of the picked, sub-optimal PV line ...

xigua commented 5 years ago

@joergoster I just ran the command again but still got "not the bestmove" bestmove :)

setoption name Skill Level value 18 ucinewgame position fen '7R/2r2pk1/p5p1/1pp3P1/8/P6R/1PP5/2K5 w - - 0 3' go depth 10 info depth 1 seldepth 1 multipv 1 score mate 1 nodes 141 nps 70500 tbhits 0 time 2 pv h3h7 info depth 2 seldepth 2 multipv 1 score mate 1 nodes 405 nps 101250 tbhits 0 time 4 pv h3h7 info depth 3 seldepth 2 multipv 1 score mate 1 nodes 597 nps 119400 tbhits 0 time 5 pv h3h7 info depth 4 seldepth 2 multipv 1 score mate 1 nodes 775 nps 155000 tbhits 0 time 5 pv h3h7 info depth 5 seldepth 2 multipv 1 score mate 1 nodes 952 nps 190400 tbhits 0 time 5 pv h3h7 info depth 6 seldepth 2 multipv 1 score mate 1 nodes 1133 nps 226600 tbhits 0 time 5 pv h3h7 info depth 7 seldepth 2 multipv 1 score mate 1 nodes 1318 nps 263600 tbhits 0 time 5 pv h3h7 info depth 8 seldepth 2 multipv 1 score mate 1 nodes 1507 nps 301400 tbhits 0 time 5 pv h3h7 info depth 9 seldepth 2 multipv 1 score mate 1 nodes 1702 nps 340400 tbhits 0 time 5 pv h3h7 info depth 10 seldepth 2 multipv 1 score mate 1 nodes 1900 nps 316666 tbhits 0 time 6 pv h3h7 bestmove a3a4 ponder b5a4

what does the pv line in each info line really means? ^_^

gvreuls commented 5 years ago

The pv line is the sequence of best moves for both players regardless of whether you set a skill level or not, so the lower you set the skill level, the smaller the chance that the real bestmove (which is the 1st move in the pv) gets played and consequentially the smaller the chance that the pv will appear on the board.

xigua commented 5 years ago

@gvreuls so pv is always from skill level=20 which is the strongest, right? Thanks for the info, very helpful. :)

gvreuls commented 5 years ago

@xigua Yes, unless you also set MultiPV to a value > 1 of course. If you set MultiPV to N you get N best pv lines, so you don't only get the best pv but also the second best (which will never be played at skill level 20), etc. (Note that setting MultiPV > 1 slows down the search.)

MichaelB7 commented 5 years ago

@xigua

Another question, how can we mimic a human player with ELO=600 (for example) using stockfish?

The best you can do is set Skill Level to 0 and with a very short time control. I believe it will still be stronger than 600 Elo. Alternatively, there are plenty of other engines that can made to play much weaker than Stockfish' weakest setting.

Micro Chess 1976 is about 600 Elo, as the name implies, it was written in 1976. I believe it can be run under an xBoard compatible GUI such as WInboard based on this link

Edit: The Microchess source appears to be faulty. HGM's Neg-2 is about 600 Elo, it compiles and works under xBoard..

#include <stdio.h>

#ifdef WIN32
#    include <windows.h>
#else
#    include <sys/time.h>
#    include <sys/times.h>
#    include <unistd.h>
int GetTickCount()
{   struct timeval t;
    gettimeofday(&t, NULL);
    return t.tv_sec*1000 + t.tv_usec/1000;
}
#endif

#define WHITE 8
#define BLACK 16
#define COLOR (WHITE|BLACK)

typedef void Func(int stm, int from, int to, void *closure);
typedef int Board[128];

int value[8] = { 0, 100, 100, 10000, 325, 350, 500, 950 };
int firstDir[] = { 0, 0, 27, 4, 18, 8, 13, 4 };
int steps[] = { -16, -15, -17, 0, 1, -1, 16, -16, 15, -15, 17, -17, 0, 1, -1, 16, -16, 0, 18, 31, 33, 14, -18, -31, -33, -14, 0, 16, 15, 17, 0 };
Board PST = {
    0, 2, 4, 6, 6, 4, 2, 0,   0,0,0,0,0,0,0,0,
    2, 8,10,12,12,10, 8, 2,   0,0,0,0,0,0,0,0,
    6,12,16,18,18,16,12, 6,   0,0,0,0,0,0,0,0,
    8,14,18,20,20,18,14, 8,   0,0,0,0,0,0,0,0,
    8,14,18,20,20,18,14, 8,   0,0,0,0,0,0,0,0,
    6,12,16,18,18,16,12, 6,   0,0,0,0,0,0,0,0,
    2, 8,10,12,12,10, 8, 2,   0,0,0,0,0,0,0,0,
    0, 2, 4, 6, 6, 4, 2, 0,   0,0,0,0,0,0,0,0
};

//              "abcdefghijklmnopqrstuvwxyz"
char pieces[] = ".5........3..4.176........";
Board board, attacks[2], lva[2];
int bestScore, bestFrom, bestTo, lastMover, lastChecker, randomize, post, iron[2], minors[2], material[2];

void
MoveGen (Board board, int stm, Func proc, void *cl)
{
    int from, to, piece, victim, type, dir, step;
    for(from=0; from<128; from = from + 9 & ~8) {
        piece = board[from];
        if(piece & stm) {
            type = piece & 7;
            if(type == 4 || type == 5) minors[!(piece & WHITE)]++, iron[!(piece & WHITE)] = from; // count minors and remember location of one
            material[!(piece & WHITE)] += value[type];
            dir = firstDir[type];
            while((step = steps[dir++])) {
                to = from;
                do {
                    to += step;
                    if(to & 0x88) break;
                    victim = board[to];
                    (*proc)(piece & COLOR, from, to, cl);
                    victim += type < 5;
                    if(!(to - from & 7) && type < 3 && (type == 1 ? to > 79 : to < 48)) victim--;
                } while(!victim);
            }
        }
    }
}

int InCheck (int stm)
{
    int k, xstm = COLOR - stm;
    for(k=0; k<128; k++) if( board[k] == stm + 3 ) {
        int dir=4, step;
        int f = (stm == WHITE ? -16 : 16); // forward
        int p = (stm == WHITE ? 2 : 1);
        if(!(k + f + 1 & 0x88) && board[k + f + 1] == xstm + p) return k + f + 2;
        if(!(k + f - 1 & 0x88) && board[k + f - 1] == xstm + p) return k + f;
        while((step = steps[dir])) {
            int from = k + steps[dir + 14];
            if(!(from & 0x88) && board[from] == xstm + 4) return from + 1;
            from = k + step;
            if(!(from & 0x88) && board[from] == xstm + 3) return from + 1;
            from = k;
            while(!((from += step) & 0x88)) if(board[from]) { // occupied
                if(dir < 8 && (board[from] & COLOR + 6) == xstm + 6) return from + 1; // R or Q and orthogonal
                if(dir > 7 && (board[from] & COLOR + 5) == xstm + 5) return from + 1; // B or Q and diagonal
                break;
            }
            dir++;
        }
        break;
    }
    return 0;
}

void
Count (int stm, int from, int to, void *cl)
{
    int s = (stm == BLACK);
    if(!(to - from & 7) && (board[from] & 7) < 3) return; // ignore Pawn non-captures
    attacks[s][to]++;
    if(lva[s][to] > value[board[from] & 7]) lva[s][to] = value[board[from] & 7];
}

void
Mark (int stm, int from, int to, void *cl)
{
    int s = (stm == BLACK);
    if(from != iron[s]) return; // only consider moves of iron piece
    attacks[s][to] += 5;        // and count its attacks as many
}

void
Score (int stm, int from, int to, void *cl)
{
    int score = PST[to] - PST[from];
    int piece = board[from];
    int victim = board[to];
    int myVal = value[piece & 7];
    int hisVal = value[victim & 7];
    int push = (piece & 7) < 3 && to - from & 7;// Pawn non-capture
    int s = (stm == BLACK);
    int check;
    if((piece & 7) < 3 && !(to - from & 7) != !victim) return; // weed out illegal pawn modes
    if((piece & 7) == 3) score -= score;        // keep King out of center
    else if(myVal > 400) score = 0;             // no centralization for R, Q
    if((piece & ~7) == (victim & ~7)) return;   // self capture
    board[from] = 0; board[to] = piece;
    if(from != lastChecker && InCheck(COLOR - stm)) score += 50; // bonus for checking with new piece
    check = InCheck(stm);                       // in check after move?
    board[to] = victim; board[from] = piece;
    if(check) return;                           // illegal
    score += ((rand()>>8 & 31) - 16)*randomize; // randomize
    if(from == lastMover) score -= 10;          // discourage moving same piece twice
    if(hisVal && hisVal < 400) score += PST[to];// centralization bonus of victim
    score += hisVal;                            // captured piece
    if(iron[!s] == to) score -= 500;            // discourage capturing last minor, to reduce stalemate probability
    if(attacks[!s][to]) {                       // to-square was attacked
        if(attacks[s][to] - 1 + push < attacks[!s][to] ) score -= myVal; else // not sufficiently protected
            if(myVal > lva[!s][to]) score += lva[!s][to] - myVal; // or protected, but more valuable
    }
    if((piece & 7) != 3 && attacks[!s][from]) { // from-square was attacked (and not King)
        if(attacks[s][from] < attacks[!s][from] ) score += myVal; else // not sufficiently protected
            if(myVal > lva[!s][from]) score -= lva[!s][from] - myVal; // or protected, but more valuable
    }
    if((piece & 7) == 1 && to < 48) score += 50;
    if((piece & 7) == 2 && to > 79) score += 50;

    if(score > bestScore) bestScore = score, bestFrom = from, bestTo = to; // remember best move
    if(post) printf("2 %d 0 1 %c%d%c%d\n", score, (from&7) + 'a', 8 - (from >> 4), (to&7) + 'a', 8 - (to >> 4));
}

int
Setup (char *fen)
{
    char c;
    int i;
    for(i=0; i<128; i++) board[i] = 0;
    i = 0;
    while((c = *fen++)) {
        if(c == 'p') board[i++] = BLACK + 2; else
            if(c >= '0' && c <= '9') i += c - '0'; else
                if(c >= 'a' && c <= 'z') board[i++] = BLACK + pieces[c - 'a'] - '0'; else
                    if(c >= 'A' && c <= 'Z') board[i++] = WHITE + pieces[c - 'A'] - '0'; else
                        if(c == '/') i = (i | 15) + 1; else break;
    }
    for(i=0; i<128; i = i + 9 & ~8) printf(i&7 ? " %2d" : "\n# %2d", board[i]); printf("\n");
    return (*fen == 'w' ? WHITE : BLACK);
}

int
main ()
{
    int stm = WHITE, engineSide = 0;
    char line[256], command[20];
    srand(GetTickCount());
    while(1) {
        int i, c;
        if(stm == engineSide) {
            char *promo = "";
            for(i=0; i<128; i++) lva[0][i] = lva[1][i] = 30000, attacks[0][i] = attacks[1][i] = 0;
            minors[0] = minors[1] = material[0] = material[1] = 0;
            MoveGen(board, COLOR, &Count, NULL);
            bestScore = -30000;
            if(material[stm == BLACK] - material[stm == WHITE] < 1000 || minors[stm == WHITE] != 1) iron[stm == WHITE] = -1;
            else MoveGen(board, COLOR-stm, &Mark, NULL);
            MoveGen(board, stm, &Score, NULL);
            board[bestTo] = board[bestFrom]; board[bestFrom] = 0; stm ^= COLOR;
            if((board[bestTo] & 7) < 3 && (stm == BLACK ? bestTo < 16 : bestTo > 111)) board[bestTo] |= 7, promo = "q"; // always promote to Q
            lastMover = bestTo;
            lastChecker = InCheck(stm) ? bestTo : -1 ;
            printf("move %c%d%c%d%s\n", (bestFrom&7) + 'a', 8 - (bestFrom >> 4), (bestTo&7) + 'a', 8 - (bestTo >> 4), promo);
        }
        fflush(stdout); i = 0;
        while((line[i++] = c = getchar()) != '\n') if(c == EOF) printf("# EOF\n"), exit(1); line[i] = '\0';
        if(*line == '\n') continue;
        sscanf(line, "%s", command);
        printf("# command: %s\n", command);
        if(!strcmp(command, "usermove")) {
            int from, to; char c, d, promo, ep;
            sscanf(line, "usermove %c%d%c%d%c", &c, &from, &d, &to, &promo);
            from = (8 - from)*16 + c - 'a'; to = (8 - to)*16 + d - 'a';
            if((board[from] & 7) == 3 && to - from == 2) board[from + 1] = board[to + 1], board[to + 1] = 0; // K-side castling
            if((board[from] & 7) == 3 && from - to == 2) board[from - 1] = board[to - 2], board[to - 2] = 0; // Q-side castling
            ep = ((board[from] & 7) < 3 && !board[to]); // recognize e.p. capture
            board[to] = board[from]; if(ep) board[from & 0x70 | to & 7] = 0; board[from] = 0;
            if(promo == 'q') board[to] = board[to] | 7; // promote
            stm ^= COLOR;
        }
        else if(!strcmp(command, "protover")) printf("feature myname=\"N.E.G. 1.2\" setboard=1 usermove=1 analyze=0 colors=0 sigint=0 sigterm=0 done=1\n");
        else if(!strcmp(command, "new"))      stm = Setup("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"), randomize = 0, engineSide = BLACK;
        else if(!strcmp(command, "go"))       engineSide = stm;
        else if(!strcmp(command, "result"))   engineSide = 0;
        else if(!strcmp(command, "force"))    engineSide = 0;
        else if(!strcmp(command, "setboard")) stm = Setup(line+9);
        else if(!strcmp(command, "random"))   randomize = !randomize;
        else if(!strcmp(command, "post"))     post = 1;
        else if(!strcmp(command, "nopost"))   post = 0;
        else if(!strcmp(command, "quit"))     break;
    }
    return 0;
}
xigua commented 5 years ago

@gvreuls got it, deeply appreciated!

xigua commented 5 years ago

thanks a lot for all the help. Now I understand it's by design where pv is always the strongest move but bestmove might vary due to different skill level setting. ^_^