0

I have been searching for a while but cant find any answer that matches my problem.

I have 2 Enums, one with cardvalues and one with Suits. Since I am trying to create a BlackJack game I would like to have Jack,Queen and King equal to 10. Right now Jacks,Queens and Kings point to 10 when using them in my game. I have also tried Jack=10, Queen=10, King=10 but when doing this J,Q,K appears as 10 which creates multiple 10s. I've checked, and either way the deck contains 52 cards.

Could someone tell me whats going one? Thanks in advance!

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

public enum Suits
{
    Hearts,
    Clubs,
    Spades,
    Diamonds
}

    public Deck()
     {
        rand = new Random();
        cardlist = new List<Card>();
        foreach (Suits s in Enum.GetValues(typeof(Suits)))
        {
            foreach (Value v in Enum.GetValues(typeof(Value)))
            {                    
                cardlist.Add(new Card(s, v));
            }
        }
       ShuffleCards();            
    }

Did something like this, but still no effect...

 public class Card
 {
    /// <summary>
    /// Variables
    /// Card has one value and one suit
    /// </summary>
     Value v;
     Suits s;

    /// <summary>
    /// Constructor
    /// </summary>
    /// <param name="siu"></param>
    /// <param name="val"></param>
    public Card ( Suits siu, string val )
    {
        Value = (Value)Enum.Parse(typeof(Value), val);
        Suits = siu;
    }

    /// <summary>
    /// Property value
    /// </summary>
    public Value Value
    {
        get { return v;}
        set { v = value; }
    }

    /// <summary>
    /// Property Suit
    /// </summary>
    public Suits Suits
    {
        get { return s; }
        set { s = value; }
    }

    /// <summary>
    /// To string method. Adding value and suit.
    /// </summary>
    /// <returns></returns>
    public override String ToString()
    {
        return Value.ToString() + " " +  Suits.ToString();
    }
}
Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
CodeKiller
  • 27
  • 3
  • 9
  • What does "dressed cards also have duplicates of different 10s" mean? – Enigmativity Sep 09 '17 at 13:54
  • 1
    That means that 10 appears instead of, J,Q,K. – CodeKiller Sep 09 '17 at 13:58
  • `Value.ToString("G")` gives you the name. `Value.ToString("D")` gives you the string of the value. – Felix Castor Sep 09 '17 at 15:02
  • You are trying to make the enum do too much work, representing both the kind of card and the value. That got you into trouble, you can map a kind to a value but you can't map a value to a kind. An enum just isn't very useful. Declare your own Card class, it should have properties like kind (so you can detect splits), a suit (doesn't actually matter in blackjack), an image (so you can update the screen) and two values. Having two values can be useful to avoid having to make the ace special. – Hans Passant Sep 09 '17 at 16:58

4 Answers4

2

Store the points in a dictionary and don't specify them in the enum:

public enum Value
{
    Ace, Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten, Jack, Queen, King
}

private Dictionary<Value, int> _pointDict = new Dictionary<Value, int>() {
    [Value.Ace] = 1,
    [Value.Two] = 2,
    ...
    [Value.Ten] = 10,
    [Value.Jack] = 10,
    [Value.Queen] = 10,
    [Value.King] = 10,
};

Then you can get the points with

int points = _pointDict[v];  // With v typed as Value

Note: I used the C# 6.0 New Feature Dictionary Initializers.

Olivier Jacot-Descombes
  • 104,806
  • 13
  • 138
  • 188
0

Sine you want to have multiple enum values for the same number (10) and then get names and add them to your List, you need to use Enum.GetNames instead of Enum.GetValues:

foreach (var v in Enum.GetNames(typeof(Value)))
{
    cardlist.Add(new Card(s, v));
}

You should also change the type of the v in the Card class to string.

Salah Akbari
  • 39,330
  • 10
  • 79
  • 109
0

In C#, an enum is a value type. Instances of value types are compared by value. Thus, enum values with the same numeric value are considered identical.

Converting an enum value to a string will yield the name of the first enum value with that numeric value. That is why Jack, Queen, and King display as "Ten". The enum values of an enum should generally be unique.

I assume that you wish to be able to get the name of a rank ("King") as well as an assigned numeric value (10). Try this:

public enum Rank
{
    Ace = 1,
    Two,
    Three,
    Four,
    Five,
    Six,
    Seven,
    Eight,
    Nine,
    Ten,
    Jack,
    Queen,
    King
}

Notice that the values for Jack, Queen, and King are unique (11, 12, 13).

This is an extension method that will return the numeric value of a rank:

public static class RankExtensions
{
    public static int GetNumericValue(this Rank rank)
    {
        return (rank < Rank.Ten) ? (int)rank : 10;
    }
}

Here is some code to demonstrate the results:

public static class Program
{
    static void Main(string[] args)
    {
        var ranks = Enum.GetValues(typeof(Rank)).Cast<Rank>();

        Console.WriteLine("Test rank with unique values:");
        foreach (Rank rank in ranks)
        {
            Console.WriteLine($"  ToString()={rank,-5}, (int)={(int)rank, 2}, GetNumericValue()={rank.GetNumericValue(), 2}");
        }
    }

And here are the results:

Test rank with unique values:
  ToString()=Ace  , (int)= 1, GetNumericValue()= 1
  ToString()=Two  , (int)= 2, GetNumericValue()= 2
  ToString()=Three, (int)= 3, GetNumericValue()= 3
  ToString()=Four , (int)= 4, GetNumericValue()= 4
  ToString()=Five , (int)= 5, GetNumericValue()= 5
  ToString()=Six  , (int)= 6, GetNumericValue()= 6
  ToString()=Seven, (int)= 7, GetNumericValue()= 7
  ToString()=Eight, (int)= 8, GetNumericValue()= 8
  ToString()=Nine , (int)= 9, GetNumericValue()= 9
  ToString()=Ten  , (int)=10, GetNumericValue()=10
  ToString()=Jack , (int)=11, GetNumericValue()=10
  ToString()=Queen, (int)=12, GetNumericValue()=10
  ToString()=King , (int)=13, GetNumericValue()=10
Brian
  • 34
  • 5
0

What you should do is use the enum Value to represent the face of the card, and not its card value.

There are two reasons. (1) As you've discovered it ends up mapping the Jack, Queen & King to all be 10's when you try to reverse the mapping from int to Value. (2) In the game of Blackjack the Ace can have two values 1 and 11. You can't have the one card represent two values in an enum so you need some other method.

First, define your enum Value like so:

public enum Value
{
    Ace = 1,
    Two, Three, Four, Five,
    Six, Seven, Eight, Nine,
    Ten, Jack, Queen, King
}

No you can define a Card class so that it can return multiple values per card, making Ace return both 1 and 11, royal cards return 10, and all other cards return their face value:

public class Card
{
    public Card(Suits suit, Value value)
    {
        this.Value = value;
        this.Suit = suit;
    }

    public Value Value { get; private set; }
    public Suits Suit { get; private set; }

    public IEnumerable<int> Values()
    {
        yield return (int)this.Value < 10 ? (int)this.Value : 10;
        if (this.Value == Value.Ace)
        {
            yield return 11;
        }
    }

    public override String ToString()
    {
        return String.Format("{0} {1}", this.Value, this.Suit);
    }
}

Now, you want to be able to score a "Hand" so make a Hand class that can hold 0 or more cards. Keep it simple by inheriting List<Card>.

public class Hand : List<Card>
{
    public Hand(IEnumerable<Card> cards)
    {
        this.AddRange(cards);
    }

    public IEnumerable<int> Values()
    {
        return ComputeValues(this.ToArray());
    }

    private IEnumerable<int> ComputeValues(Card[] cards)
    {
        if (cards.Length == 0)
        {
            return Enumerable.Empty<int>();
        }
        else if (cards.Length == 1)
        {
            return cards[0].Values();
        }
        else
        {
            return
                cards[0]
                    .Values()
                    .SelectMany(
                        v => ComputeValues(cards.Skip(1).ToArray()),
                        (v, n) => v + n)
                    .Distinct();
        }
    }
}

Now ComputeValues does the heavy lifting of computing the possible values of a hand. I'll show some results at the end of the answer.

Finally, you need a Deck class to represent the entire set of cards. That's simply just an extension of the Hand class.

public class Deck : Hand
{
    private static Random rand = new Random();

    public Deck() : base(
        from Suits s in Enum.GetValues(typeof(Suits))
        from Value v in Enum.GetValues(typeof(Value))
        orderby rand.Next()
        select new Card(s, v))
    { }
}

Notice that the creation and shuffling of the deck is built in to the constructor.

Now it's easy to put all of this together. So if I want to take two cards from the deck I can do this:

var deck = new Deck();

var hand = new Hand(deck.Take(2));

Console.WriteLine(String.Join(" + ", hand.Select(c => c.ToString())));
Console.WriteLine(String.Join(" OR ", hand.Values()));

When run I get results like this:

Six Spades + Jack Hearts
16

or:

Ace Hearts + Jack Clubs
11 OR 21

If I change it to getting 3 cards using .Take(3), and I run enough time, I eventually got this:

Ace Diamonds + Ace Hearts + Four Spades
6 OR 16 OR 26
Enigmativity
  • 113,464
  • 11
  • 89
  • 172