TransWikia.com

Getting wrong results in perft stats with checks and mates

Chess Asked by user24225 on October 5, 2021

The perft count works well after testing with many positions from epd files from the web

Now I want to see some perft stats like this one: https://www.chessprogramming.org/Perft_Results, from the initial position

But I’m getting bad results for checks and mates, in the wiki says in the initial position in the depth 4 there are 8 mates but I get that result in the depth 5, same for the the depth 5 in the wiki says 347 but I get that in the depth 6 and it should be 10828, what I’m doing wrong?

Here is the program output with perft to depth 6: https://pastebin.com/3DSVn9UZ

Here is the code:

typedef struct perft_stats_s {
    uint64_t captures;
    uint64_t en_passant;
    uint64_t castles;
    uint64_t promotions;
    uint64_t checks;
    uint64_t discovery_checks;
    uint64_t double_checks;
    uint64_t checkmates;
} perft_stats_s;

typedef struct perft_data_s {
    perft_stats_s stats[1];
    uint64_t nodes;
    uint64_t elapsed;
} perft_data_s;

void UpdateStats(move_t move, bool is_capture, bool in_check, board_s *board, perft_stats_s *stats)
{
    if (in_check)
    {
        uint64_t checks = attacksToKing(board);
        if (popCount(checks) == 1) {
            ++stats->checks;
            uint64_t to_sq = bb_sq(TO_SQ(move));
            if (to_sq != checks) {
                ++stats->discovery_checks;
            }
        }
        else {
            ++stats->double_checks;
        }
    }

    if (is_capture)
        ++stats->captures;
    if (MoveType(move) == MT_EP_CAPTURE) {
        ++stats->en_passant;
        ++stats->captures;
    }
    if (MoveType(move) == MT_CASTLE)
        ++stats->castles;
    if (MoveType(move) >= QUEEN_PROMOTE)
        ++stats->promotions;
}

uint64_t PerftStats(uint8_t depth, bool in_check, board_s *board, perft_stats_s *stats) {

    ASSERT(checkBoard(board));

    move_t list[MAX_MOVES];
    uint8_t count;

    if (in_check)
    {
        move_t *first = list;
        move_t *end = generateEvasion(board, list);
        count = end - first;
    }
    else
    {
        count = generateAllMoves(board, list);
    }

    uint64_t nodes = 0;
    uint8_t m;
    move_t move;
    bool is_capture;
    
    if (depth == 1) 
    {
        for (m = 0; m < count; ++m) 
        {
            move = list[m];
            is_capture = board->pieces[TO_SQ(move)] != EMPTY;
            if (!makeMove(board, move))  {
                continue;
            }
            bool inCheck = isInCheck(board);
            UpdateStats(move, is_capture, inCheck, board, stats);
            ++nodes;
            unmakeMove(board);
        }
        return nodes;
    }

    for (m = 0; m < count; ++m) 
    {
        move = list[m];
        is_capture = board->pieces[TO_SQ(move)] != EMPTY;
        if (!makeMove(board, move))  {
            continue;
        }
        bool inCheck = isInCheck(board);
        uint64_t new_nodes = PerftStats(depth - 1, inCheck, board, stats);
        UpdateStats(move, is_capture, inCheck, board, stats);
        if (inCheck && new_nodes == 0) {
            ++stats->checkmates;
        } else 
            nodes += new_nodes;
        unmakeMove(board);
    }
    return nodes;
}

void PerftStatsRoot(uint8_t depth, board_s *board)
{
    perft_data_s data[MAX_DEPTH];
    memset(data, 0, sizeof(perft_data_s) * MAX_DEPTH);
    
    perft_stats_s stats[1];
    memset(stats, 0, sizeof(perft_stats_s) * 1);

    uint64_t start = getTime();

    printf("n");
    printf(" depth                 nodes    elapsed msn");

    uint64_t totalNodes = 0;
    uint8_t d;

    bool in_check = isInCheck(board);

    //for (d = 1; d <= depth; d++) 
    for (d = depth; d > 0; --d) 
    {
        uint64_t sp = getTime();
        uint64_t nodes = PerftStats(d, in_check, board, stats);
        totalNodes += nodes;

        memcpy(data[d].stats, stats, sizeof(perft_stats_s) * 1);
        data[d].nodes = nodes;
        data[d].elapsed = getTime() - sp;

        memset(stats, 0, sizeof(perft_stats_s) * 1);
    }

    for (d = depth; d > 0; --d)
    {
        perft_data_s *curr_data = &data[d];
        perft_data_s *prev_data = &data[d - 1];
        curr_data->stats->captures -= prev_data->stats->captures;
        curr_data->stats->en_passant -= prev_data->stats->en_passant;
        curr_data->stats->castles -= prev_data->stats->castles;
        curr_data->stats->promotions -= prev_data->stats->promotions;
        curr_data->stats->checks -= prev_data->stats->checks;
        curr_data->stats->discovery_checks -= prev_data->stats->discovery_checks;
        curr_data->stats->double_checks -= prev_data->stats->double_checks;
        curr_data->stats->checkmates -= prev_data->stats->checkmates;
    }

    for (d = 1; d <= depth; ++d) 
    {
        perft_data_s *curr_data = &data[d];
        printf("%6d  %20s %10" PRIu64 "n", d, formatNumber(curr_data->nodes), curr_data->elapsed);
        perft_stats_s *st = curr_data->stats;
        printf("    caps: %" PRIu64 "n", st->captures);
        printf("    enpa: %" PRIu64 "n", st->en_passant);
        printf("    cast: %" PRIu64 "n", st->castles);
        printf("    prom: %" PRIu64 "n", st->promotions);
        printf("    chec: %" PRIu64 "n", st->checks);
        printf("    dich: %" PRIu64 "n", st->discovery_checks);
        printf("    doch: %" PRIu64 "n", st->double_checks);
        printf("    chmt: %" PRIu64 "n", st->checkmates);
    }
    
    uint64_t elapsed = getTime() - start;
    uint64_t nps = NPS(elapsed, totalNodes);

    printf("n");
    printf("depth       : %un", depth);
    printf("nodes       : %sn", formatNumber(totalNodes));
    printf("nps         : %sn", formatNumber(nps));
    printf("time        : %" PRIu64 "msn", elapsed);
}

I save the result in an array struct and after that I loop over the array to update the counters to show the correct counters, like this:

counter[depth] -= counter[depth - 1]

One Answer

It doesn't look like you're counting mates at the leaves. Your depth == 1 code is almost the same as the rest, except that counting mates is omitted. This would explain why your mate counts lag behind as you described.

My suggestion would be to get rid of the depth == 1 block entirely (since to make it correct would require it to be exactly the same as the code immediately below it) and instead add a if(depth <= 0) return 1 at the top of PerftStats

Answered by Jeff Wilson on October 5, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP