1.题目:C++使用srand(seed)实现一个抽卡概率
1.题目描述
实现一个抽卡逻辑。传入的是一个数组,数组的每一位的索引代表这个卡的类型,数字代表这个卡的概率,举例,如果[1,1,1] 数组,就代表0,1,2 三种卡的,抽中的概率分别是30% ,30% ,30%。
2.基础知识
1.srand()和 rand()
srand() 函数用于设置随机数种子,rand() 函数用于生成随机数。
srand() 函数需要传入一个种子,种子不同,生成的随机数也不同。如果这个种子是固定的话,则生成的随机数也会是固定的。所以我们需要使用时间作为种子,这样每次运行程序的时间都不同,生成的随机数也不同。
srand(time(0))
2.概率计算:累积概率法实现
概率计算:
假设我们有 3 个卡片,概率分别为 30%、40%、30%,对应输入(3,4,3)。
累积概率:
卡片 0:30% ,权重3
卡片 1:40% ,权重4
卡片 2:30% ,权重3
如何实现卡片对应的概率:
如果随机数在 1 到 3,抽中卡片 0。
如果随机数在 4 到 7,抽中卡片 1。
如果随机数在 8 到 10,抽中卡片 2.
随机数为1到10
举例:
如果随机数是2,for 循环第一次就返回了卡片 0,30%
如果随机数是5,for 只有循环到第二次。70%-30%=40%
如果随机数是9,for循环循环到第三次。100%-30%-40%=30%
2.C++逻辑实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
| #include <iostream> #include <cstdlib> #include <ctime>
int sample(const int probabilities[], int size) { int totalWeight = 0; for (int i = 0; i < size; ++i) { totalWeight += probabilities[i]; } if (totalWeight == 0) { return -1; } int randomNum = rand() % totalWeight + 1; int cumulativeWeight = 0; for (int i = 0; i < size; ++i) { cumulativeWeight += probabilities[i]; if (randomNum <= cumulativeWeight) { return i; } } return size - 1; }
int main() { srand(time(0)); int cardProbabilities[] = {1, 1, 1}; int arraySize = sizeof(cardProbabilities) / sizeof(cardProbabilities[0]); std::cout << "=== 抽卡模拟 ===" << std::endl; std::cout << "卡片概率权重: "; for (int i = 0; i < arraySize; ++i) { std::cout << "卡片" << i << "(" << cardProbabilities[i] << ") "; } std::cout << std::endl; int totalWeight = 0; for (int i = 0; i < arraySize; ++i) { totalWeight += cardProbabilities[i]; } std::cout << "实际概率: "; for (int i = 0; i < arraySize; ++i) { double percentage = (double)cardProbabilities[i] / totalWeight * 100; std::cout << "卡片" << i << "(" << percentage << "%) "; } std::cout << std::endl << std::endl; std::cout << "抽卡结果:" << std::endl; for (int i = 0; i < 10; ++i) { int result = sample(cardProbabilities, arraySize); std::cout << "第" << (i+1) << "次抽卡: 获得卡片" << result << std::endl; } return 0; }
|
游戏中的实际应用示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
| #include <iostream> #include <string> #include <cstdlib> #include <ctime>
struct Card { int id; std::string name; std::string rarity; int weight; Card() : id(0), name(""), rarity(""), weight(0) {} Card(int i, const std::string& n, const std::string& r, int w) : id(i), name(n), rarity(r), weight(w) {} };
class CardPool { private: static const int MAX_CARDS = 10; Card cards[MAX_CARDS]; int weights[MAX_CARDS]; int cardCount; public: CardPool() : cardCount(0) {} void addCard(const Card& card) { if (cardCount < MAX_CARDS) { cards[cardCount] = card; weights[cardCount] = card.weight; cardCount++; } } Card drawCard() { int totalWeight = 0; for (int i = 0; i < cardCount; ++i) { totalWeight += weights[i]; } int randomNum = rand() % totalWeight; int currentSum = 0; for (int i = 0; i < cardCount; ++i) { currentSum += weights[i]; if (randomNum < currentSum) { return cards[i]; } } return cards[cardCount - 1]; } void showPool() { std::cout << "\n=== 卡池信息 ===" << std::endl; int totalWeight = 0; for (int i = 0; i < cardCount; ++i) { totalWeight += weights[i]; } for (int i = 0; i < cardCount; ++i) { double probability = (double)weights[i] / totalWeight * 100; std::cout << cards[i].name << " (" << cards[i].rarity << ") - " << probability << "%" << std::endl; } } };
int main() { srand(time(0)); CardPool pool; pool.addCard(Card(1, "普通剑士", "普通", 50)); pool.addCard(Card(2, "精英法师", "稀有", 30)); pool.addCard(Card(3, "传说龙骑", "史诗", 15)); pool.addCard(Card(4, "神话英雄", "传说", 4)); pool.addCard(Card(5, "至尊神器", "神话", 1)); pool.showPool(); std::cout << "\n=== 抽卡结果 ===" << std::endl; for (int i = 0; i < 10; ++i) { Card drawnCard = pool.sample(); std::cout << "第" << (i+1) << "抽: " << drawnCard.name << " (" << drawnCard.rarity << ")" << std::endl; } return 0; }
|
核心要点总结
- 概率计算: 数组中的数值是权重,实际概率 = 权重 / 总权重
- 随机数生成: 使用
rand() % totalWeight
生成随机数
- 区间查找: 通过累积权重确定随机数落在哪个卡片区间
- 边界处理: 注意数组越界和权重为0的情况
- 测试验证: 通过大量测试验证概率分布的正确性
这种实现方式在游戏开发中非常常用,可以灵活调整各种卡片的出现概率,适用于抽卡、掉落、随机事件等场景。