在C#中表示游戏卡类的最佳方式

我使用类卡,其中包含2个枚举属性(套件 – 心形钻石黑桃和俱乐部)和卡值从2到A.并覆盖ToString()方法返回类似Ah Ad等等。一切正常但枚举值无法启动有了数字,因此枚举的卡片值看起来像x2,x3,x4 ……它不漂亮。

还需要简单的方法来解析单个字符串中的几张卡片。

谁知道设计这门课程的最佳方法?

难道你不能将Jack,Queen,King和Ace分别分别为11,12,13和14吗? 它最终看起来像:

public class Card { public int Value { get; private set; } public enum SuitType { Clubs, Spades, Hearts, Diamonds } public SuitType Suit { get; private set; } public Card(int value, SuitType suit) { Suit = suit; Value = value; } public Card(string input) { if (input == null || input.Length < 2 || input.Length > 2) throw new ArgumentException(); switch (input[0]) { case 'C': case 'c': Suit = SuitType.Clubs; break; case 'S': case 's': Suit = SuitType.Spades; break; case 'H': case 'h': Suit = SuitType.Hearts; break; case 'D': case 'd': Suit = SuitType.Diamonds; break; default: throw new ArgumentException(); } int uncheckedValue = (int)input[1]; if (uncheckedValue > 14 || uncheckedValue < 1) throw new ArgumentException(); Value = uncheckedValue; } public string encode() { string encodedCard = ""; switch (Suit) { case SuitType.Clubs: encodedCard += 'c'; break; case SuitType.Spades: encodedCard += 's'; break; case SuitType.Hearts: encodedCard += 'h'; break; case SuitType.Diamonds: encodedCard += 'd'; break; } encodedCard += (char) Value; return encodedCard; } public override string ToString() { string output = ""; if (Value > 10) { switch (Value) { case 11: output += "Jack"; break; case 12: output += "Queen"; break; case 13: output += "King"; break; case 14: output += "Ace"; break; } } else { output += Value; } output += " of " + System.Enum.GetName(typeof(SuitType), Suit); return output; } } 

编辑:我添加了一些字符串function。 我从Jon Hanna的回答中获取了Card(string input)结构。

pip卡有一个明显的数值,我们可以添加J = 10,Q = 11,K = 12。

根据正在建模的游戏,使A = 13比A = 1更方便(因此可以更简单地计算手的不同相对值)。

枚举没有真正的优势,特别是因为枚举允许超出范围的值,除非您明确检查它们(例如,没有什么可以阻止某人将(CardValue)54分配给卡值枚举值)。

ToString可以使用值{null,"1","2","3","4","5","6","7","8","9","10","J","Q","K"} 。 同样地, {'♥','♦','♠','♣'}可以提供更好的输出。

解析总是比输出字符串更棘手,即使你对接受的内容非常严格,因为你必须处理无效输入的可能性。 一个简单的方法是:

 private Card(string input) { if(input == null) throw new ArgumentNullException(); if(input.length < 2 || input.length > 3) throw new ArgumentException(); switch(input[input.Length - 1]) { case 'H': case 'h': case '♥': _suit = Suit.Hearts; break; case 'D': case 'd': case '♦': _suit = Suit.Diamonds; break; case 'S': case 's': case '♠': _suit = Suit.Spades; break; case 'C': case 'c': case '♣': _suit = Suit.Clubs; break; default: throw new ArgumentException(); } switch(input[0]) { case "J": case "j": _cardValue = 11; break; case "Q": case "q": _cardValue = 12; break; case "K": case "k": _cardValue = 13; break; case "A": case "a": _cardValue = 1; break; default: if(!int.TryParse(input.substring(0, input.Length - 1), out _cardValue) || _cardValue < 2 || _cardVaue > 10) throw new ArgumentException; break; } } public static Card Parse(string cardString) { return new Card(cardString); } 

您可能希望添加一个读取较大字符串的静态方法,在解析时生成yield return卡,以便更容易编码多个卡。

当我第一次开始使用card.dll时,我使用的是套装和卡片排名,但后来我不想处理同样的问题并编写额外的代码来补偿字符串,因为我写了一个摘要class Info只有两个变量(Flag(byte))和(Name(string))由Rank类和Suit类实现,它们将是Card类的成员。 我发现这对命名约定和过滤目的更有效。 我喜欢使用枚举但是必须解决变量命名问题可能很麻烦,所以有时最好不要将变量名称作为字符串。

因此,当卡构造函数被调用时,输入卡ID,然后它进入Rank和Suit,然后将ID分离代码中的含义(101 = 100(套装标志)+ 1(等级标志))。 受保护的抽象SetName(int cardID)和SetFlag(int cardID),同时通过Rank和Suit处理info的构造函数中的其余部分。 枚举没有更多问题,它仍然可以通过Flag按数字过滤。

该卡命名系统使用1到4 * 100(告诉套装标志)+ 1到13(用于卡等级)。 500 + 14到16分别是Little Joker,Big Joker和Wild。

 public class Card { short id; public Card(string zFile) { this.id = Convert.ToInt16(zFile.Split('.')[0].Trim()); this.Rank = new Rank(id); this.Suit = new Suit(id); } public override string ToString() { if (Suit.Flag == 5) return Suit.Name; return string.Concat(Rank.Name, " of ", Suit.Name); } public override int GetHashCode() { return id; } public Rank Rank { get; private set; } public Suit Suit { get; private set; } public static Card GetGreaterRank(Card value1, Card value2) { return (value1.Rank >= value2.Rank) ? value1 : value2; } public static bool CompareRank(Card value1, Card value2) { return (value1.Rank.Flag == value2.Rank.Flag); } public static bool CompareSuit(Card value1, Card value2) { return (value1.Suit.Flag == value2.Suit.Flag); } }; public abstract class Info { protected Info(short cardID) { Flag = SetFlag(cardID); } protected string SetName(short cardID, params string[] names) { for (int i = 0; i < names.Length; i++) { if (Flag == (i + 1)) return names[i]; } return "Unknown"; } protected abstract byte SetFlag(short cardID); public static implicit operator byte(Info info) { return info.Flag; } public byte Flag { get; protected set; } public string Name { get; protected set; } }; public class Rank : Info { internal Rank(short cardID) : base(cardID) { string name = SetName(cardID, "A","2","3","4","5","6","7", "8","9","10","J","Q","K","Little Joker","Big Joker","Wild"); Name = (name == "Unknown") ? string.Concat(name, " Rank") : name; } protected override byte SetFlag(short cardID) { return Convert.ToByte(cardID.ToString().Remove(0, 1)); } }; public class Suit : Info { internal Suit(short cardID) : base(cardID) { string name = SetName(cardID,"Clubs","Diamonds","Hearts","Spades"); Name = (name == "Unknown") ? string.Concat(name, " Suit") ? name; } protected override byte SetFlag(short cardID) { return Convert.ToByte(cardID.ToString().Remove(1)); } }; 

所以,现在如果您的卡片图像文件名为101.png并将其传递给Card ctor,它将传递给Rank和Suit获取您的信息。 实际上你只是在为图像文件提供名称的代码(数字)。

我可能会从2个枚举开始,1代表Suits,1代表Faces。 然后根据这些枚举声明公共属性“Suit”和公共属性“Face”。 您可能还需要一个具有卡可以具有的不同唯一值的数组(即1到13)。

您可以使用数字启动枚举(尽管首选从零开始)

 public enum Card { Two = 2, Three, Four, ... } 

抓我之前写的,这更好。

 using System; enum Suit { Clubs, Hearts, Diamonds, Spades } class Card { Suit Suit { get; private set; } int Value { get; private set; } Card(Suit suit, int value) { Suit = suit; Value = value; } private const string[] valsToString = new string[] { "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A" }; bool IsValid() { return Value >= 2 && Value <= 14; } override string ToString() { return string.Format("{0} of {1}", valsToString[Value - 2], Suit); } }