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

C++如何从多数组抽取随机变量实现21点游戏不重复抽牌

实现方案

首先先对你现有代码做一处小调整,方便后续属性匹配:你当前结构体里的cardSuit定义为char类型,但你存储的花色是字符串,建议修改为int类型存对应数组的索引,后续要展示花色/牌面/状态时直接用索引取对应数组的值即可,修改后的结构体如下:

struct DefineCard {
    int cardSuit; // 存cardSuits数组的索引,0=clubs,1=spades以此类推
    int cardFace; // 存cardFaces数组的索引
    int cardValue; // 卡牌点数
    int cardStatus; // 存cardStatus数组的索引,0=in play,1=in deck,2=discarded
} Deck[52]; // 标准一副牌只有52张,不需要53

步骤1:初始化整副牌

在main函数里先给Deck数组的所有元素赋值,生成完整的牌堆:

// 初始化牌堆
int cardIndex = 0;
for(int suit = 0; suit < 4; suit++) { // 遍历4种花色
    for(int face = 0; face < 13; face++) { // 遍历13种牌面
        Deck[cardIndex].cardSuit = suit;
        Deck[cardIndex].cardFace = face;
        Deck[cardIndex].cardValue = cardValue[face];
        Deck[cardIndex].cardStatus = 1; // 初始状态为在牌堆里
        cardIndex++;
    }
}

步骤2:用Fisher-Yates洗牌算法打乱牌堆

这是最常用的公平洗牌算法,打乱后按顺序抽卡就能保证不会重复,不需要额外判断卡牌状态。
首先要设置随机数种子,放在main函数最开头即可:

srand(time(0)); // 初始化随机数种子,全局只需要调用一次

然后实现洗牌逻辑:

// 洗牌逻辑
for(int i = 51; i > 0; i--) {
    int j = rand() % (i + 1); // 生成0到i之间的随机数
    // 交换两张牌的位置
    DefineCard temp = Deck[i];
    Deck[i] = Deck[j];
    Deck[j] = temp;
}

步骤3:抽卡实现

定义一个抽卡指针,记录当前抽到第几张牌,每次抽卡直接取指针位置的卡牌,指针自增即可:

int drawPointer = 0; // 抽卡指针,初始指向牌堆第一张

// 抽卡逻辑
DefineCard drawCard() {
    DefineCard drawnCard = Deck[drawPointer];
    drawnCard.cardStatus = 0; // 标记为已使用
    drawPointer++;
    return drawnCard;
}

抽出来的卡牌可以直接用属性对应你定义的数组展示,比如要打印卡牌信息:

DefineCard myCard = drawCard();
cout << "抽到的卡牌:" << cardSuits[myCard.cardSuit] << " " << cardFaces[myCard.cardFace] << ",点数:" << myCard.cardValue << endl;

可选实现方案

如果你不想用洗牌的方式,也可以每次生成0-51的随机数,判断对应卡牌的cardStatus是否为1(在牌堆),如果是就抽走标记为0,如果不是就重新生成随机数。不过这种方式在牌堆剩的牌少的时候可能会多次循环,效率不如洗牌法高,更推荐用洗牌的方式实现。

内容的提问来源于stack exchange,提问作者Finn Marshall

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 11:15:08