Jody Stocks
Jody Stocks

Reputation: 93

Randomly generating from a dictionary and returning the key and value

This is a 2 part question, I am making a blackjack game and I am trying to randomly generate a key and value (KEY = string(card value e.g. Hearts2), And VALUE = int (Score for that specific card value)), and I would like to try and return the key and value.

I have a deck, dealer and player class. My Deck class has 2 methods, Deck() and Shuffel(), deck() is used to create the deck and shuffle90 well shuffles the deck(). I would like to send the random card to the dealer class to deal the cards. I am not sure if it is possible to return the key and value so the dealer class method (dealCards()) can receive a string and int as parameters.

Also I found a way to randomize my dictionary but it is returning the entire dictionary randomized, but I only need one card to be returned.

This is what I have so far for the Deck class...

This is my

public static Dictionary<string, int> deck()
{
    string[] Suite = new string[4] { "Spades", "Clubs", "Hearts", "Diamonds" };
    string[] FaceValue = new string[13] { "A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K" };
    int score;

    Dictionary<string, int> deckOfCards = new Dictionary<string, int>();

    for (int s = 0; s < 4; s++)
    {
        string sute = Suite[s];

        for (int f = 0; f < 13; f++)
        {
           string fV = FaceValue[f];

            if (f == 0)
            {
                score = 0;
            }
            else if (f >= 9)
            {
                score = 10;
            }
            else
            {
                score = (f + 1);
            }

            string card = (sute + fV);

            deckOfCards.Add(card, score);
        }
    }


    Dictionary<string, int> ranCard = deckOfCards.Shuffle();

    return ranCard;
}

As you can see I created 2 simple arrays and used for loops to iterate through them and add them to the dictionary.

The last two lines, the first is declaring a new dictionary to hold the random card and reciving its value from the Shuffle() method,(is posted bellow) and I would like to know if there is a way to return ranCard.Key, ranCard.Value ? so I can have my Dealer class method like this (dealCard(string card, int score))?

This is my Shuffle() method for my Deck class...

public static Dictionary<TKey, TValue> Shuffle<TKey, TValue>(this Dictionary<TKey, TValue> Cards)
{
    Random r = new Random();
    Cards = Cards.OrderBy(x => r.Next(0, Cards.Count)).ToDictionary(item => item.Key, item => item.Value);
    return Cards;
}

Now with this method The entire dictionary is randomized and I would like to just return one randome value if possible. I tried to remove the parameters in the r.Next(**) but still the same.

I am using vs2012.

Upvotes: 1

Views: 1147

Answers (2)

pid
pid

Reputation: 11607

First things first.

The game rules require that you have state. What I mean is that you don't have a stateless random return value, but you MUST retain the state across the generation of random values, as the probabilities change. In layman's terms: you can't draw the same card more than n times because the game rules specify how the deck is composed.

That said, it is clear that one way or another you have to keep track of the cards in the deck. In your code you shuffle the whole deck and return that. All you need now is an object that wraps it and keeps internally its state, like so:

class Dealer
{
    private List<Card> shuffledCards; // keep state of the current shuffle

    public Dealer(...)
    {
        shuffledCards = Shuffle(...); // use your method to get the shuffled cards
    }

    public Card Deal() // remove the first card from the deck and hand it out
    {
        Card c;

        c = shuffledCards[0];
        shuffledCards.RemoveAt(0);

        return c;
    }
}

There are many more ways to implement this, at least another 2 come to my mind, but the result is just the same.

Upvotes: 1

Jon Skeet
Jon Skeet

Reputation: 1503290

There are several issues here:

  • Dictionaries aren't ordered - so the order in which the cards come out of OrderBy may not be reflected when you iterate over the dictionary later. I believe in the current implementation it may happen to do that, but fundamentally you shouldn't rely on it.
  • Your way of shuffling isn't good anyway - it's likely to make early items stay early, as if there are two items which get the same random "key", the earlier one will be emitted first. Consider using a variant of a Fisher-Yates shuffle - there are several examples on SO, such as this one.
  • Your approach to keeping the card and score together as a dictionary key/value pair feels awkward to me... if you avoid that, you'll find a lot of other things drop out.

Basically, a deck of cards isn't a dictionary - it's a sequence of cards. So you should be modelling a card:

public sealed class Card
{
    // Fields for face value and suit, and a property to compute the score
}

How you choose to represent the face value and suit are up to you, but you should consider using enums given that there are natural sets of valid values here.

Once you've got a deck as a List<Card> (or a Queue<Card>), you can easily shuffle that, and then just deal Card values to players.

Upvotes: 1

Related Questions