billforsternz / thc-chess-library

General Purpose Rules of Chess Library for C++
MIT License
38 stars 13 forks source link

perft #13

Closed Disservin closed 2 years ago

Disservin commented 2 years ago

Shouldnt that return 400 for depth 2 ? Always returns 4200 for me. Sorry if thats the wrong place to ask here. Read more about Perft on Chessprogramming Wiki `

    int perf(int depth) {  
        int nodes = 0;   
        if (depth == 0) {  
            return 1;  
        }
        else {
            cr.GenLegalMoveList(moves, check, mate, stalemate);
            unsigned int len = moves.size();
            for (unsigned int i = 0; i < len; i++) {
                thc::Move mv = moves[i];
                std::string mv_txt = mv.NaturalOut(&cr);
                if (mv_txt != "--") {
                    cr.PlayMove(mv);
                    nodes += perf(depth - 1);
                    cr.PopMove(mv);
                }
            }
            return nodes;
        }
    }

`

billforsternz commented 2 years ago

I've actually never done this exercise, I have heard about it and had lingering anxiety that I should try it and check that my code copes well. Thanks for pushing me over the edge; Although my code is battle hardened and I was confident in it, I was still very relieved to find that everything matches the standard numbers reported in https://www.chessprogramming.org/Perft_Results !

I'm not sure what you are doing with the mv.NaturalOut() and the comparison. Here is a complete but minimally altered version of your code that works well;

static thc::ChessRules cr;

int perf(int depth) { int nodes = 0; if (depth == 0) { return 1; } else { std::vector moves; std::vector check; std::vector mate; std::vector stalemate; cr.GenLegalMoveList(moves, check, mate, stalemate); unsigned int len = moves.size(); for (unsigned int i = 0; i < len; i++) { thc::Move mv = moves[i]; cr.PlayMove(mv); nodes += perf(depth - 1); cr.PopMove(mv); } return nodes; } }

int main( int argc, char *argv[] ) { for( int i=1; i<=7; i++ ) { cr.Forsyth("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"); int n = perf(i); printf( "perf(cr,%d) = %d\n", i, n ); } return 0; }

Here is a version that's closer to the reference in the wiki page you link to (importantly it uses 64 bit integers, for example). This version is a bit more optimised too, especially the "PerftFast" version which uses the pseudo legal move refinement suggested in the Wiki (possible because my move generator does work in the way discussed - by generating all moves including moves that illegally leave the king exposed to capture). I did have to make a tiny tweak to thc.h to make the fast version possible, I had to make function GenMoveList() public rather than protected.

typedef unsigned long long u64; u64 Perft( thc::ChessRules &cr, int depth ); u64 PerftFast( thc::ChessRules &cr, int depth );

int main( int argc, char *argv[] ) { for( int i=1; i<=max; i++ ) { thc::ChessRules cr; u64 n = PerftFast(cr,i); printf( "PerftFast(cr,%d) = %lld\n", i, n ); } return 0; }

u64 Perft( thc::ChessRules &cr, int depth ) { thc::MOVELIST movelist; int n_moves, i; u64 nodes = 0;

if( depth == 0 )
    return 1ULL;

cr.GenLegalMoveList( &movelist );
n_moves = movelist.count;
for( i=0; i<n_moves; i++)
{
    cr.PushMove( movelist.moves[i] );
    nodes += Perft( cr, depth-1 );
    cr.PopMove( movelist.moves[i] );
}
return nodes;

}

u64 PerftFast( thc::ChessRules &cr, int depth ) { thc::MOVELIST movelist; int n_moves, i; u64 nodes = 0;

if( depth == 0 )
    return 1ULL;

cr.GenMoveList( &movelist );
n_moves = movelist.count;
for( i=0; i<n_moves; i++)
{
    cr.PushMove( movelist.moves[i] );
    bool okay = cr.Evaluate();
    if( okay )
        nodes += PerftFast( cr, depth-1 );
    cr.PopMove( movelist.moves[i] );
}
return nodes;

}

I got these results, matching https://www.chessprogramming.org/Perft_Results ;

PerftFast(cr,1) = 20 PerftFast(cr,2) = 400 PerftFast(cr,3) = 8902 PerftFast(cr,4) = 197281 PerftFast(cr,5) = 4865609 PerftFast(cr,6) = 119060324 PerftFast(cr,7) = 3195901860

On my old slow laptop PerftFast(cr,7) took 6 minutes. Level 8 takes at least an hour, I'll leave it running overnight. I also tried the "Kiwipete" position and pleasingly got;

Perft(cr,1) = 48 Perft(cr,2) = 2039 Perft(cr,3) = 97862 Perft(cr,4) = 4085603 Perft(cr,5) = 193690690

As expected.

On Mon, 24 Jan 2022 at 09:00, disservin @.***> wrote:

Shouldnt that return 400 for depth 2 ? Always returns 4200 for me. Sorry if thats the wrong place to ask here. Read more about Perft on Chessprogramming Wiki https://www.chessprogramming.org/Perft `

int perf(int depth) {
    int nodes = 0;
    if (depth == 0) {
        return 1;
    }
    else {
        cr.GenLegalMoveList(moves, check, mate, stalemate);
        unsigned int len = moves.size();
        for (unsigned int i = 0; i < len; i++) {
            thc::Move mv = moves[i];
            std::string mv_txt = mv.NaturalOut(&cr);
            if (mv_txt != "--") {
                cr.PlayMove(mv);
                nodes += perf(depth - 1);
                cr.PopMove(mv);
            }
        }
        return nodes;
    }
}

`

— Reply to this email directly, view it on GitHub https://github.com/billforsternz/thc-chess-library/issues/13, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABSQYSV473AVZYXUD2E7OXDUXRM5BANCNFSM5MTX4BAA . Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.

You are receiving this because you are subscribed to this thread.Message ID: @.***>

-- Bill Forster 15A Boundary Road Kelburn Wellington 6012 New Zealand +64 21 357 371 @.***

Disservin commented 2 years ago

Hey thanks for the quick replay, your altered version works just fine, the comparison was done because I wanted to see the current move, mv std::cout << mv_text << std::enl; However sometimes I didnt get a move back but got "--". Which I thought is some kind of bug ? So I simply tried to skip that part. Great that perft confirmed the move generation. !

billforsternz commented 2 years ago

Thanks. I did check one more level;

PerftFast(cr,1) = 20 Date/time is: Mon Jan 24 23:25:26 2022 PerftFast(cr,2) = 400 Date/time is: Mon Jan 24 23:25:26 2022 PerftFast(cr,3) = 8902 Date/time is: Mon Jan 24 23:25:26 2022 PerftFast(cr,4) = 197281 Date/time is: Mon Jan 24 23:25:26 2022 PerftFast(cr,5) = 4865609 Date/time is: Mon Jan 24 23:25:26 2022 PerftFast(cr,6) = 119060324 Date/time is: Mon Jan 24 23:25:39 2022 PerftFast(cr,7) = 3195901860 Date/time is: Mon Jan 24 23:31:24 2022 PerftFast(cr,8) = 84998978956 Date/time is: Tue Jan 25 02:07:39 2022

Also;

Perft(cr,1) = 20 Date/time is: Tue Jan 25 02:07:39 2022 Perft(cr,2) = 400 Date/time is: Tue Jan 25 02:07:39 2022 Perft(cr,3) = 8902 Date/time is: Tue Jan 25 02:07:39 2022 Perft(cr,4) = 197281 Date/time is: Tue Jan 25 02:07:39 2022 Perft(cr,5) = 4865609 Date/time is: Tue Jan 25 02:07:40 2022 Perft(cr,6) = 119060324 Date/time is: Tue Jan 25 02:07:55 2022 Perft(cr,7) = 3195901860 Date/time is: Tue Jan 25 02:15:10 2022 Perft(cr,8) = 84998978956 Date/time is: Tue Jan 25 05:22:34 2022

Finally the "Kiwipete" position to one more level too;

PerftFast(cr,1) = 48 Date/time is: Tue Jan 25 07:47:57 2022 PerftFast(cr,2) = 2039 Date/time is: Tue Jan 25 07:47:57 2022 PerftFast(cr,3) = 97862 Date/time is: Tue Jan 25 07:47:57 2022 PerftFast(cr,4) = 4085603 Date/time is: Tue Jan 25 07:47:58 2022 PerftFast(cr,5) = 193690690 Date/time is: Tue Jan 25 07:48:17 2022 PerftFast(cr,6) = 8031647685 Date/time is: Tue Jan 25 08:02:14 2022

Conclusion: All node counts match reference values from https://www.chessprogramming.org/Perft_Results. On my 12 year old creaky Acer laptop Level 8 for the opening position takes 3 hours 7 minutes (default), or 2 hours 36 (pseudo move optimisation) - not as big a speedup as I would have guessed actually. Each level takes 20-30 times longer than the previous level (makes sense, about the average number of moves in a position), so I could probably go Kiwipete level 7 in about 8 hours. Not sure whether I'll bother as there's no reference value to compare against. But I am motivated to resolve the 2645 or 2637? question about double checks in the Kiwipete position! I might do it on the weekend, it just needs an int AttackedSquareCount() type function to supplement the existing bool AttackedSquare().

On Mon, 24 Jan 2022 at 22:32, disservin @.***> wrote:

Hey thanks for the quick replay, your altered version works just fine, the comparison was done because I wanted to see the current move, mv std::cout << mv_text << std::enl; However sometimes I didnt get a move back but got "--". Which I thought is some kind of bug ? So I simply tried to skip that part. Great that perft confirmed the move generation. !

— Reply to this email directly, view it on GitHub https://github.com/billforsternz/thc-chess-library/issues/13#issuecomment-1019894503, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABSQYSVV5DJ53QYGXXKB5OLUXUMBJANCNFSM5MTX4BAA . Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.

You are receiving this because you commented.Message ID: @.***>

-- Bill Forster 15A Boundary Road Kelburn Wellington 6012 New Zealand +64 21 357 371 @.***

billforsternz commented 2 years ago

One more level of Kiwipete;

PerftFast(cr,1) = 48 Date/time is: Tue Jan 25 07:47:57 2022 PerftFast(cr,2) = 2039 Date/time is: Tue Jan 25 07:47:57 2022 PerftFast(cr,3) = 97862 Date/time is: Tue Jan 25 07:47:57 2022 PerftFast(cr,4) = 4085603 Date/time is: Tue Jan 25 07:47:58 2022 PerftFast(cr,5) = 193690690 Date/time is: Tue Jan 25 07:48:17 2022 PerftFast(cr,6) = 8031647685 Date/time is: Tue Jan 25 08:02:14 2022 PerftFast(cr,7) = 374190009323 Date/time is: Tue Jan 25 19:32:49 2022

On Mon, 24 Jan 2022 at 22:32, disservin @.***> wrote:

Hey thanks for the quick replay, your altered version works just fine, the comparison was done because I wanted to see the current move, mv std::cout << mv_text << std::enl; However sometimes I didnt get a move back but got "--". Which I thought is some kind of bug ? So I simply tried to skip that part. Great that perft confirmed the move generation. !

— Reply to this email directly, view it on GitHub https://github.com/billforsternz/thc-chess-library/issues/13#issuecomment-1019894503, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABSQYSVV5DJ53QYGXXKB5OLUXUMBJANCNFSM5MTX4BAA . Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.

You are receiving this because you commented.Message ID: @.***>

-- Bill Forster 15A Boundary Road Kelburn Wellington 6012 New Zealand +64 21 357 371 @.***