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

时间:2011-03-18 12:39:18

标签: c# architecture enums

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

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

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

7 个答案:

答案 0 :(得分:4)

难道你不能将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;
    }
}

修改 我添加了一些字符串功能。 我从Jon Hanna's answer获取Card(string input)的结构。

答案 1 :(得分:2)

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

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

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

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

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

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卡,以便更容易编码多张卡。

答案 2 :(得分:1)

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

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

答案 3 :(得分:1)

此卡命名系统使用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获取您的信息。实际上你只是在为图像文件提供名称的代码(数字)。

答案 4 :(得分:0)

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

答案 5 :(得分:0)

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

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

答案 6 :(得分:0)

抓一下我之前写的,这样更好。

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);
    }
}