2

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 ms\n");

    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       : %u\n", depth);
    printf("nodes       : %s\n", formatNumber(totalNodes));
    printf("nps         : %s\n", formatNumber(nps));
    printf("time        : %" PRIu64 "ms\n", 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]
2
  • 1
    I'm afraid this question is about programming and should be answered in a programming site. Specifying the code is Java would have been great help too
    – David
    Jul 18 '20 at 21:16
  • 2
    questions about programming engines are on-topic, per chess.meta.stackexchange.com/q/418/9025
    – Herb
    Jul 19 '20 at 0:56
1

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

1
  • I just found a mistake, in the UpdateStats the checks should be incremented after the if (in_check) now is showing the correct stats count except that mates are in the wrong depth, I guess I have to update manually, here I see that the last depth 6 the check and mate are ommited
    – user24225
    Jul 21 '20 at 0:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy