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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 13:24:27