C#控制台纸牌洗牌器开发:Deck类公共方法实现咨询
C# 控制台纸牌程序 Deck 类实现方案
核心设计前提
Deck类需要维护一个私有集合存储当前剩余的卡牌,模拟真实牌堆的状态,禁止外部直接修改牌堆内容。选择List<Card>作为存储结构,支持动态增删元素,适配发牌、抽牌后移除卡牌的需求。
三个公共方法实现逻辑
1. InitStandardDeck 方法
- 初始化前先清空牌堆内残留的卡牌,避免重复初始化导致牌数异常
- 遍历4种花色,依次生成A、2-10、J、Q、K共13张牌,凑齐标准52张牌
- 采用Fisher-Yates 原地洗牌算法打乱牌堆顺序,该算法随机性有严格数学保障,时间复杂度O(n),比随机排序、Guid排序的偏差更小
- 随机数实例声明为类级静态字段,仅实例化一次,避免短时间内多次创建Random实例导致种子重复、洗牌结果不随机的问题
2. DealHand 方法
- 先做边界校验:如果当前剩余卡牌不足2张,自动调用初始化方法重置牌堆,适配循环抽牌的场景,避免索引越界(如果需要牌空时抛出异常可自行替换逻辑)
- 因为初始化时牌堆已经完全打乱,不需要每次发牌再随机选位置,直接从牌堆末尾取2张牌即可(List移除末尾元素时间复杂度为O(1),性能远高于移除开头元素,逻辑上和真实牌堆从顶拿牌完全等价)
- 取出的卡牌从牌堆集合中移除后,打包为列表返回
3. DrawACard 方法
- 同样先做边界校验:剩余卡牌不足1张时自动重置牌堆
- 从牌堆末尾取1张牌,从集合移除后直接返回
完整可运行Deck类代码
将以下代码替换你现有代码中的空Deck类即可:
public class Deck { // 存储牌堆当前剩余的所有卡牌 private readonly List<Card> _cards = new List<Card>(); // 全局唯一随机数实例,避免短时间重复实例化导致随机序列重复 private static readonly Random _rng = new Random(); /// <summary> /// 初始化标准52张牌堆并完成洗牌 /// </summary> public void InitStandardDeck() { // 清空原有牌堆 _cards.Clear(); // 遍历4种花色生成所有卡牌 foreach (Card.SUIT suit in Enum.GetValues(typeof(Card.SUIT))) { // 生成A,默认值为1,可根据二十一点等规则自行调整为1/11 _cards.Add(new Card("A", suit, 1)); // 生成2-10的数字牌 for (int num = 2; num <= 10; num++) { _cards.Add(new Card(num.ToString(), suit, num)); } // 生成J/Q/K人头牌,默认值为10 _cards.Add(new Card("J", suit, 10)); _cards.Add(new Card("Q", suit, 10)); _cards.Add(new Card("K", suit, 10)); } // Fisher-Yates 洗牌算法 int remainCount = _cards.Count; while (remainCount > 1) { remainCount--; int randomIndex = _rng.Next(remainCount + 1); // 交换当前位置和随机位置的卡牌 Card temp = _cards[randomIndex]; _cards[randomIndex] = _cards[remainCount]; _cards[remainCount] = temp; } } /// <summary> /// 发放2张手牌,发出的牌从牌堆移除 /// </summary> public List<Card> DealHand() { // 牌量不足时自动重置牌堆 if (_cards.Count < 2) { InitStandardDeck(); } List<Card> hand = new List<Card>(2); for (int i = 0; i < 2; i++) { // 取牌堆最后一张(性能最优) Card card = _cards[^1]; hand.Add(card); _cards.RemoveAt(_cards.Count - 1); } return hand; } /// <summary> /// 抽取1张牌,抽出的牌从牌堆移除 /// </summary> public Card DrawACard() { // 牌空时自动重置 if (_cards.Count < 1) { InitStandardDeck(); } Card card = _cards[^1]; _cards.RemoveAt(_cards.Count - 1); return card; } }
额外说明
- 你现有Card类的SUIT枚举中
Dimonds为拼写错误,正确拼写为Diamonds,不影响程序运行但建议修正。 - 代码中A的默认值设为1,如果你要做二十一点类的游戏,可以自行修改A的赋值逻辑,增加软手判断即可。
- 取牌时选择List末尾元素是性能优化选择,因为牌堆已经是完全随机的,取任意固定位置的概率都均等,不存在公平性问题。
内容的提问来源于stack exchange,提问作者NK2030
相关产品推荐
相关产品推荐

