C# 扑克牌:它们应该是枚举、结构还是类?
我正在设计一个游戏网站,许多(希望有数千)玩家将同时玩某些纸牌游戏。牌组为standart 52牌组。每张牌都有一套西装和一个等级。这些牌将一直被洗牌、交易、挑选、订购和玩。我的问题是,C# 扑克牌:它们应该是枚举、结构还是类?,c#,struct,C#,Struct,我正在设计一个游戏网站,许多(希望有数千)玩家将同时玩某些纸牌游戏。牌组为standart 52牌组。每张牌都有一套西装和一个等级。这些牌将一直被洗牌、交易、挑选、订购和玩。我的问题是,Card应该是枚举、结构还是类 对于枚举: 让每个卡都是一个字节0..51。因此,一张卡片将占用很少的空间。可以将手表示为8字节的位集。当需要时,你可以很快计算出一张牌的花色和等级:即花色(n)=n/13。这将是非常有效的。如果您需要为卡片编写方法,请通过扩展方法编写 对于结构: 不,那就像是在写机器代码。卡片
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*/}
}
通过这种方式,甲板尺寸是固定的,脸和西装是用尽可能少的代码创建的(尽管我相信有人能想出一种方法来解决这个问题)。我不相信你在这里问的问题是正确的。如何代表你的卡应该是一个问题,你想做什么,你的卡决定;通过现在回答如何表示您的卡的问题,您会自动约束自己,以解决您稍后将遇到的其他更有趣/更具挑战性的问题
您真正应该考虑的是如何实现程序的行为。比如说
- 发“牌”时会发生什么?是否要表示在持有这些卡的实体之间物理移动的卡?(例如,牌组、玩家的手牌、弃牌堆、桌子等),或者您希望这些实体仅引用一个中央牌库?或者使用完全独立的计数机制
- 你打算如何“订购”卡片?您选择实施的游戏可能有不同的规则(例如王牌低或高?皇家套装是否都有相同的价值?是否会有王牌?)这些可能是您的决定