You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何改进随机发牌程序以避免重复输出卡牌?

如何改进随机发牌程序以避免重复输出卡牌?

嘿,我明白你遇到的问题了——随机发牌时重复输出确实很头疼,你尝试用布尔值回滚的思路方向是对的,但可能逻辑没捋顺。我给你两种靠谱的解决方案,你可以根据需求来选:

方法一:用标记数组记录已发卡牌

这个思路最直观,就是用一个二维数组来标记已经发过的牌,每次生成新牌前先检查是否已经被发过,如果重复就重新生成,直到拿到没发过的牌。

修改后的代码如下:

#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#define SUITS 4
#define RANKS 13

int main() {
    int num_cards, rank, suit;
    const char rank_code[] = {'2', '3', '4', '5', '6', '7', '8', '9', 't', 'j', 'q', 'k', 'a'};
    const char suit_code[] = {'c', 'd', 'h', 's'};
    // 创建标记数组,初始化为0(0表示未发,1表示已发)
    int dealt[SUITS][RANKS] = {0};

    srand(time(NULL));

    printf("Enter number of cards in hand: ");
    scanf("%d", &num_cards);
    // 先做个简单的输入校验,避免超过总牌数
    if (num_cards < 1 || num_cards > SUITS * RANKS) {
        printf("Invalid number! Please enter between 1 and 52.\n");
        return 1;
    }

    printf("Your hand: \n");
    for (int i = 0; i < num_cards; ) {
        suit = rand() % SUITS;
        rank = rand() % RANKS;
        // 检查这张牌是否未被发过
        if (!dealt[suit][rank]) {
            dealt[suit][rank] = 1; // 标记为已发
            printf("%c%c ", rank_code[rank], suit_code[suit]);
            i++; // 只有拿到有效牌才递增循环变量
        }
        // 如果重复了,就不递增i,重新生成
    }
    printf("\n");
    return 0;
}

这里要注意,我把循环里的i++移到了拿到有效牌的分支里——如果生成了重复牌,就不递增i,让循环重新生成,这样就不用手动回滚i了,逻辑更清晰。另外加了个输入校验,防止用户输入超过52的数。

方法二:Fisher-Yates洗牌算法(更高效)

如果要发的牌数量接近52张,方法一可能会因为重复生成随机数导致效率降低。这时候用Fisher-Yates洗牌算法就更合适:先把所有牌放在一个数组里,打乱顺序后直接取前N张,完全不会有重复问题。

代码示例:

#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#define SUITS 4
#define RANKS 13
#define TOTAL_CARDS (SUITS * RANKS)

int main() {
    int num_cards;
    const char rank_code[] = {'2', '3', '4', '5', '6', '7', '8', '9', 't', 'j', 'q', 'k', 'a'};
    const char suit_code[] = {'c', 'd', 'h', 's'};
    // 创建数组存储所有牌的索引(0-51)
    int deck[TOTAL_CARDS];
    
    srand(time(NULL));

    printf("Enter number of cards in hand: ");
    scanf("%d", &num_cards);
    if (num_cards < 1 || num_cards > TOTAL_CARDS) {
        printf("Invalid number! Please enter between 1 and 52.\n");
        return 1;
    }

    // 初始化牌组
    for (int i = 0; i < TOTAL_CARDS; i++) {
        deck[i] = i;
    }

    // Fisher-Yates洗牌
    for (int i = TOTAL_CARDS - 1; i > 0; i--) {
        int j = rand() % (i + 1);
        // 交换i和j位置的元素
        int temp = deck[i];
        deck[i] = deck[j];
        deck[j] = temp;
    }

    printf("Your hand: \n");
    // 取前num_cards张牌
    for (int i = 0; i < num_cards; i++) {
        int card = deck[i];
        int suit = card / RANKS;
        int rank = card % RANKS;
        printf("%c%c ", rank_code[rank], suit_code[suit]);
    }
    printf("\n");
    return 0;
}

这个方法的优势是不管发多少牌,效率都很高,而且逻辑上完全避免了重复,因为我们是从打乱的完整牌组里取牌,和现实中洗牌发牌的逻辑一致。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.08 09:30:29