C# 扑克牌:它们应该是枚举、结构还是类?

C# 扑克牌:它们应该是枚举、结构还是类?,c#,struct,C#,Struct,我正在设计一个游戏网站,许多(希望有数千)玩家将同时玩某些纸牌游戏。牌组为standart 52牌组。每张牌都有一套西装和一个等级。这些牌将一直被洗牌、交易、挑选、订购和玩。我的问题是,Card应该是枚举、结构还是类 对于枚举: 让每个卡都是一个字节0..51。因此,一张卡片将占用很少的空间。可以将手表示为8字节的位集。当需要时,你可以很快计算出一张牌的花色和等级:即花色(n)=n/13。这将是非常有效的。如果您需要为卡片编写方法,请通过扩展方法编写 对于结构: 不,那就像是在写机器代码。卡片

我正在设计一个游戏网站,许多(希望有数千)玩家将同时玩某些纸牌游戏。牌组为standart 52牌组。每张牌都有一套西装和一个等级。这些牌将一直被洗牌、交易、挑选、订购和玩。我的问题是,
Card
应该是枚举、结构还是类

  • 对于枚举: 让每个卡都是一个字节0..51。因此,一张卡片将占用很少的空间。可以将手表示为8字节的位集。当需要时,你可以很快计算出一张牌的花色和等级:即花色(n)=n/13。这将是非常有效的。如果您需要为卡片编写方法,请通过扩展方法编写

  • 对于结构: 不,那就像是在写机器代码。卡片结构简单,存储的数据很少,不可变,体积小。它没有太多的行为,所以将其作为一个结构,并将其视为一个被动数据结构。当需要时,你可以很快地从一张给定的卡片中计算出0..51中的索引

  • 上课时间: 不,这不是一种面向对象的思维方式。做一个卡片课。使其不可变。创建52个实例。让卡池容纳这些实例。因此,当一个人需要黑桃皇后时,它会向牌池索要。即使有数千场比赛在进行,黑桃皇后也只有一个。如果需要,在卡片中存储索引字段0..51

我倾向于最后一个选项(类),但我不确定。我不太担心表现;在这一过程中,我可能会犯更严重的错误。我担心的是我的整个观点可能是错误的;也许这是一个很容易的决定,我犹豫了,因为我缺乏其他人所拥有的知识

你觉得怎么样


编辑:关于卡片的行为。我想一张牌只会知道其他的牌。例如,它可以定义“谁在桥牌上击败谁”的偏序。它不需要知道关于甲板的任何事情。这将是服务器端代码;当然,它不需要知道如何在屏幕上绘制自己等。

您可以将每张卡表示为一个数字,然后将它们包装在一个枚举和一个类中。如果0到51之间的每个数字代表一张卡,则您可以拥有一个枚举:

public enum Card
{
   HeartsAce = 0,
   Hearts2 = 1,
   // ... and so on
}

int nCard = 16;
Card myCard = (Card)nCard;
你也可以上一节课:

public class Card
{
    private readonly int _nSuitNumber = 0;
    private readonly int _nCardNumber = 0;

    public Card(int a_nNumber)
    {
        _nSuitNumber = a_nNumber / 13;  // 1 = Hearts, 2 = Diamonds ...
        _nCardNumber = a_nNumber % 13;  // 1 = ace, 2 = two
    }
}
或者最好把它们结合起来

public class Card
{
    private readonly Suit _suit;
    private readonly Value _value;

    public Card(int a_nNumber)
    {
        _suit = (Suit)(a_nNumber / 13);  // 0 = Hearts, 1 = Diamonds ...
        _value = (Value)(a_nNumber % 13 + 1);  // 1 = ace, 2 = two
    }

    public Suit Suit
    {
        get { return _suit; }
    }

    public Value Value
    {
        get { return _value; }
    }

    public int ToNumber()
    {
        return (int)_suit * 13 + ((int)_value - 1);
    }
}

public enum Suit
{
    Hearts = 0,
    Diamonds = 1,
    Clubs = 2,
    Spades = 3
}

public enum Value
{
    Ace = 1,
    Two = 2,
    Three = 3,
    Four = 4,
    Five = 5,
    Six = 6,
    Seven = 7,
    Eight = 8,
    Nine = 9,
    Ten = 10,
    Jack = 11,
    Queen = 12,
    King = 13,
}

使用此类,您可以同时使用数字(0-52)和类。该类只不过是数字的包装器。您可以根据需要向类添加任何操作、方法和属性。当您存储或传输数据时,您只需要使用数字。

为卡制作一个
结构或
类,卡的值应该是
枚举
,卡的套装也是
枚举


制作一个甲板,你可以使用<代码>类< /代码>,它包含了一个列表:<代码>卡<代码> >,它的操作如<代码> Suffle 等。

< p>你可以考虑你试图构建什么抽象。如果一张卡是由其他函数传递的低级对象,则更简单的
enum
可能更合适,但如果您希望一张卡能够
draw()
本身或其他功能,则需要更复杂的功能。这张卡将如何适合您的应用程序?

我认为这个问题在逻辑上是可以回答的。我将从面向对象的角度来看它。我认为一张卡片有两个子元素,套装和价值。这些可能应该是
enum
。一手牌(类)可能应该包含一个卡片列表,这让我相信最好将卡片作为结构或类。为了确定一只手是否有一对,这将是hand类的一个函数


由于多人玩不同类型的游戏,每副牌都必须知道它有什么类型的牌以及有多少张牌。但即使在这种情况下,卡本身也是不可变的。

我会使用枚举使用类或结构,并在其上放置一个内部构造函数:

publlic class PlayingCard
{
    internal PlayingdCard(CardSuit suit, CardFace face)
    {
        this.Suit = suit;
        this.Face = face;
    } 

    public CardSuit Suit { get; private set; }

    public CardFace Face { get; private set; }
}
定义牌组类来管理牌,但(最重要的是)让它在构建期间分配牌:

public class Deck
{
    private List<PlayingCard> cards = new List<PlayingCard>();
    public Deck()
    {
        for(var i = 0; i < 4; i++)
        {
            for (var j = 1 to 13)
            {
                this.cards.Add(new PlayingCard((CardSuit)i, (CardFace)j));
            }
        }
    }

    public void Shuffle() { /* implement me */ }
    public PlayingCard GetNextCard() { /* implement me */ }

}
公共类甲板
{
私有列表卡=新列表();
公共甲板()
{
对于(变量i=0;i<4;i++)
{
对于(变量j=1至13)
{
此.cards.Add(新游戏卡((CardSuit)i,(CardFace)j));
}
}
}
public void Shuffle(){/*实现me*/}
公共播放卡GetNextCard(){/*实现me*/}
}

通过这种方式,甲板尺寸是固定的,脸和西装是用尽可能少的代码创建的(尽管我相信有人能想出一种方法来解决这个问题)。

我不相信你在这里问的问题是正确的。如何代表你的卡应该是一个问题,你想做什么,你的卡决定;通过现在回答如何表示您的卡的问题,您会自动约束自己,以解决您稍后将遇到的其他更有趣/更具挑战性的问题

您真正应该考虑的是如何实现程序的行为。比如说

  • 发“牌”时会发生什么?是否要表示在持有这些卡的实体之间物理移动的卡?(例如,牌组、玩家的手牌、弃牌堆、桌子等),或者您希望这些实体仅引用一个中央牌库?或者使用完全独立的计数机制

  • 你打算如何“订购”卡片?您选择实施的游戏可能有不同的规则(例如王牌低或高?皇家套装是否都有相同的价值?是否会有王牌?)这些可能是您的决定