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
相关产品推荐
相关产品推荐

