user-1: 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]


user23985: 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: <p>The perft count works well after testing with many positions from epd files from the web</p>
<p>Now I want to see some perft stats like this one: <a href="https://www.chessprogramming.org/Perft_Results" rel="nofollow noreferrer">https://www.chessprogramming.org/Perft_Results</a>, from the initial position</p>
<p>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?</p>
<p>Here is the program output with perft to depth 6: <a href="https://pastebin.com/3DSVn9UZ" rel="nofollow noreferrer">https://pastebin.com/3DSVn9UZ</a></p>
<p>Here is the code:</p>
<pre><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-&gt;checks;
            uint64_t to_sq = bb_sq(TO_SQ(move));
            if (to_sq != checks) {
                ++stats-&gt;discovery_checks;
            }
        }
        else {
            ++stats-&gt;double_checks;
        }
    }

    if (is_capture)
        ++stats-&gt;captures;
    if (MoveType(move) == MT_EP_CAPTURE) {
        ++stats-&gt;en_passant;
        ++stats-&gt;captures;
    }
    if (MoveType(move) == MT_CASTLE)
        ++stats-&gt;castles;
    if (MoveType(move) &gt;= QUEEN_PROMOTE)
        ++stats-&gt;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 &lt; count; ++m) 
        {
            move = list[m];
            is_capture = board-&gt;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 &lt; count; ++m) 
    {
        move = list[m];
        is_capture = board-&gt;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 &amp;&amp; new_nodes == 0) {
            ++stats-&gt;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(&quot;\n&quot;);
    printf(&quot; depth                 nodes    elapsed ms\n&quot;);

    uint64_t totalNodes = 0;
    uint8_t d;

    bool in_check = isInCheck(board);

    //for (d = 1; d &lt;= depth; d++) 
    for (d = depth; d &gt; 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 &gt; 0; --d)
    {
        perft_data_s *curr_data = &amp;data[d];
        perft_data_s *prev_data = &amp;data[d - 1];
        curr_data-&gt;stats-&gt;captures -= prev_data-&gt;stats-&gt;captures;
        curr_data-&gt;stats-&gt;en_passant -= prev_data-&gt;stats-&gt;en_passant;
        curr_data-&gt;stats-&gt;castles -= prev_data-&gt;stats-&gt;castles;
        curr_data-&gt;stats-&gt;promotions -= prev_data-&gt;stats-&gt;promotions;
        curr_data-&gt;stats-&gt;checks -= prev_data-&gt;stats-&gt;checks;
        curr_data-&gt;stats-&gt;discovery_checks -= prev_data-&gt;stats-&gt;discovery_checks;
        curr_data-&gt;stats-&gt;double_checks -= prev_data-&gt;stats-&gt;double_checks;
        curr_data-&gt;stats-&gt;checkmates -= prev_data-&gt;stats-&gt;checkmates;
    }

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

    printf(&quot;\n&quot;);
    printf(&quot;depth       : %u\n&quot;, depth);
    printf(&quot;nodes       : %s\n&quot;, formatNumber(totalNodes));
    printf(&quot;nps         : %s\n&quot;, formatNumber(nps));
    printf(&quot;time        : %&quot; PRIu64 &quot;ms\n&quot;, elapsed);
}
</code></pre>
<p>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:</p>
<pre><code>counter[depth] -= counter[depth - 1]
</code></pre>
 23985: <p>It doesn't look like you're counting mates at the leaves.  Your <code>depth == 1</code> code is <em>almost</em> the same as the rest, except that counting mates is omitted.  This would explain why your mate counts lag behind as you described.</p>
<p>My suggestion would be to get rid of the <code>depth == 1</code> 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 <code>if(depth &lt;= 0) return 1</code> at the top of <code>PerftStats</code></p>
