Лучший способ представить класс игровой карты в C # - PullRequest
5 голосов
/ 18 марта 2011

Я использую класс Card, который содержит 2 перечисляемых свойства (suite - червы и бубны червы) и значение карты от 2 до A. И переопределяет метод ToString (), возвращая что-то вроде Ah Ad и т. Д. Все в порядке, но значение enum может не начинается с числа, поэтому перечисленные значения моей карты выглядят как x2, x3, x4 ... это не красиво.

Также необходим простой подход для разбора нескольких карт из одной строки.

Кто знает лучший подход к оформлению этого класса?

Ответы [ 7 ]

4 голосов
/ 18 марта 2011

Не могли бы вы назначить Джека, Королеву, Короля и Туза равными 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;
    }
}

Edit: Я добавил некоторые строковые функции. Я взял структуру Card(string input) из ответа Джона Ханны .

2 голосов
/ 18 марта 2011

Существует очевидное числовое значение для пип-карт, и мы можем добавить J = 11, Q = 12, K = 13.

Может быть удобнее иметь A = 14, чем 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 карты при ее разборе, чтобы упростить кодирование нескольких карт.

1 голос
/ 28 июля 2011

Эта система именования карт использует от 1 до 4 * 100 (говорит о масте масти) + от 1 до 13 (для ранга карты).От 500 + 14 до 16 - Маленький Джокер, Большой Джокер и Дикий.

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 и он передается в ctor, он передается в Ранги костюм получить информацию для вас.На самом деле все, что вы делаете, давая файлу изображения код (числовой) для имени.

1 голос
/ 27 июля 2011

Когда я впервые запустил card.dll, я использовал перечисления для мастей и ранжирования карт, но потом мне не хотелось иметь дело с той же проблемой и писать дополнительный код для компенсации строк, поэтому янаписал абстрактный класс Info только с двумя переменными (Flag (byte)) и (Name (string)), которые будут реализованы классом Rank и классом Suit, которые будут членами класса Card.Я обнаружил, что это работает намного лучше для соглашений об именах и для целей фильтрации.Я люблю использовать перечисления, но необходимость обходить именование переменных может быть хлопотной, поэтому иногда лучше не получать имя переменной в виде строки.

Поэтому, когда конструктор Card вызывается, идентификатор картывводится и затем переходит в ранг и костюм, которые затем разделяют значение идентификатора в коде (101 = 100 (флаг костюма) + 1 (флаг ранга)).Защищенные абстрактные SetName (int cardID) и SetFlag (int cardID) обрабатывают все остальное в конструкторе информации через Rank и Suit.Больше нет проблем с перечислением, и оно все равно может быть отфильтровано по номеру с помощью флага.

0 голосов
/ 18 марта 2011

Поцарапайте то, что я написал раньше, это лучше.

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);
    }
}
0 голосов
/ 18 марта 2011

Вы можете начать перечисления с номера (хотя предпочтительно начинать с нуля)

public enum Card
{
   Two = 2,
   Three,
   Four,
   ...
}
0 голосов
/ 18 марта 2011

Я бы, вероятно, начал с 2 перечислений, 1 представляющих костюмы и 1 представляющих лица.Затем объявите публичную собственность "Suit" и публичную собственность "Face" на основе этих перечислений.Вам также, вероятно, понадобится массив с различными уникальными значениями, которые может иметь карта (т. Е. От 1 до 13).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...