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>

/**
* 抽卡函数 - 累积概率法
* @param probabilities 概率数组,每个元素代表对应索引卡片的权重
* @param size 数组大小
* @return 抽中的卡片索引
*/
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; // 无效输入
}

// 生成随机数 [1, totalWeight]
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));

// 示例:[1,1,1] 代表3种卡,每种概率相等(各33.33%)
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;

// 进行10次抽卡测试
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;
}

核心要点总结

  1. 概率计算: 数组中的数值是权重,实际概率 = 权重 / 总权重
  2. 随机数生成: 使用 rand() % totalWeight 生成随机数
  3. 区间查找: 通过累积权重确定随机数落在哪个卡片区间
  4. 边界处理: 注意数组越界和权重为0的情况
  5. 测试验证: 通过大量测试验证概率分布的正确性

这种实现方式在游戏开发中非常常用,可以灵活调整各种卡片的出现概率,适用于抽卡、掉落、随机事件等场景。