Click here to Skip to main content
15,907,395 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I am trying to create a deck of cards and have the cards shuffled when the user picks one up, however part of my code just doesn't want to cooperate with me and give me a "An object reference is required for the non-static field, method, or property 'BlackJackDeck.Shuffle()'. Below are the codes.

C#
public class BlackJackHand : Hand

public override void Write(int x, int y)
        {
            if (IsDealer)
            {  
                int i = 0;
                foreach (ICard _card in _cards)
                {
                    BlackJackDeck.Shuffle(); //<This is the error line.
                    _card.Write(x + i, y);
                    x += 6;
                    if (x>= 76)
                    {
                        x = 0;
                        y += 4;
                    }
                }
            }
            else
            {
                base.Write(x, y);
                Console.SetCursorPosition(x = 20, y);
                Console.WriteLine(Score);
            }
        }


C#
public class BlackJackDeck : Deck

public override void Shuffle()
        {
            Random rnd = new Random();
            for (int i = 0; i < _cards.Count; i++)
            {
                int j = rnd.Next(_cards.Count);
                ICard temp = _cards[i];
                _cards[i] = _cards[j];
                _cards[j] = temp;
            }
        }


What I have tried:

I've tried deck.shuffle(), _deck.shuffle and a few others.
Posted
Updated 12-Nov-22 13:05pm
v2
Comments
PIEBALDconsult 11-Nov-22 23:49pm    
You need to instantiate a Deck and then Shuffle() that.
Plus, don't keep reinstantiating the Random, make one static instance and always use that.
Graeme_Grant 12-Nov-22 7:13am    
I have a better method of shuffling/randomizing lists that does not use Random... see below ;)
PIEBALDconsult 12-Nov-22 10:42am    
I shuffle a deck differently as well. Though I wrote such only as an exercise, I never wrote a card-based game. Looking through my files I see that I tried it in C++ in 1996 and then in C# in 2003.
The C# version uses a System.Security.Cryptography.RNGCryptoServiceProvider.
I have classes Dealables <- Cards <- PlayingCards , plus Shoe and Hand, etc.
A Shoe is instantiated with the number decks to create and the number of jokers to include.
But I never shuffle the cards in the shoe, I just draw a random card from the shoe.
Graeme_Grant 12-Nov-22 10:47am    
I have used many different methods too. For this, what I used made the most sense. Blackjack is usually 3 or 5 decks, depending on where the casino is... I just put together a simple system that could be used for any card game. I was just too lazy to include the joker as I am not into making card games.
PIEBALDconsult 12-Nov-22 15:05pm    
Having played Blackjack in Vegas many times...
You used to be able to find single-deck games, but not so much anymore. I think they might still have double-deck games in the high limit areas. I'm unsure I ever saw a four-deck shoe in use. Mostly I've seen six-deck shoes.
When I was developing my code I had no particular game in mind, really just a playing card module which could be used by multiple games.

I'll do half the job for you - the deck, dealer and the hand objects. You need to add the game logic.

1. Card object
C#
public enum Kind
{
    Two,
    Three,
    Four,
    Five,
    Six,
    Seven,
    Eight,
    Nine,
    Ten,
    Jack,
    Queen,
    King,
    Ace,
}

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

public class Card : IComparable<Card>
{
    public Kind Kind;
    public Suit Suit;

    public Card(Kind kind, Suit suit)
    {
        Kind = kind;
        Suit = suit;
    }

    public int CompareTo(Card? other)
        => other == null
            ? 1
            : Suit != other.Suit
                ? Suit.CompareTo(other.Suit)
                : Kind.CompareTo(other.Kind);

    public override string ToString()
        => $"{Kind} of {Suit}";
}

2. CardSorter for custom sort ordering
C#
public enum CardSortType
{
    KindOnly,
    SuitOnly,
    SuitThenKind,
    KindThenSuit,
}

public class CardSorter : IComparer<Card>
{
    public CardSorter(CardSortType sortBy = CardSortType.SuitThenKind)
        => SortBy = sortBy;

    public CardSortType SortBy { get; init; }

    public int Compare(Card x, Card y)
    {
        switch (SortBy)
        {
            case CardSortType.KindOnly:
                return x.Kind.CompareTo(y.Kind);
            case CardSortType.SuitOnly:
                return x.Suit.CompareTo(y.Suit);
            case CardSortType.SuitThenKind:
                if (x.Suit != y.Suit) return x.Suit.CompareTo(y.Suit);
                return x.Kind.CompareTo(y.Kind);
            case CardSortType.KindThenSuit:
                if (x.Kind != y.Kind) return x.Kind.CompareTo(y.Kind);
                return x.Suit.CompareTo(y.Suit);
            default:
                throw new NotImplementedException($"CardOrderMethod {SortBy} is not implemented.");
        }
    }
}

3. CardDeck for managing the deck
C#
public class CardDeck
{
    public CardDeck()
        => Cards = Enum.GetValues(typeof(Suit))
            .Cast<Suit>()
            .SelectMany(_ => Enum.GetValues(typeof(Kind)).Cast<Kind>(),
                (suit, kind) => new { suit, kind })
            .Select(card => new Card(card.kind, card.suit))
            .ToList();

    public List<Card> Cards { get; private set; }


    public int Count => Cards.Count;

    public Card DrawCardAt(int index)
    {
        if (index < 0 || index >= Count)
            throw new ArgumentOutOfRangeException(nameof(index));

        Card card = Cards[index];
        Cards.RemoveAt(index);
        return card;
    }

    public Card DrawTopCard()
        => DrawCardAt(0);

    public Card DrawBottomCard()
        => DrawCardAt(Count - 1);

    public Card DrawRandomCard()
    {
        Random random = new Random();
        int index = random.Next(Count);
        return DrawCardAt(index);
    }

    public void AddCardOnTop(Card card)
    {      
        if (Cards.Contains(card))
            throw new InvalidOperationException($"Deck already contains card {card}.");

        Cards.Insert(0, card);
    }

    public void AddCardOnBottom(Card card)
    {
        if (!Cards.Contains(card))
        {
            Cards.Add(card);
            return;
        }
        throw new InvalidOperationException($"Deck already contains card {card}.");
    }

    public void Shuffle()
        => Cards = Cards.OrderBy(x => Guid.NewGuid()).ToList();

    public void Sort()
        => Cards.Sort();

    public void Sort(IComparer<Card> comparer)
        => Cards.Sort(comparer);
}

4. Hand to hold the Cards:
C#
public class Hand
{
    public Hand(string name)
        => Name = name;

    public List<Card> Cards { get; private set; } = new();
    
    public string Name { get; set; }

    public void AddCard(Card card)
    {
        if (Cards.Contains(card))
            throw new InvalidOperationException($"Hand already contains card {card}.");

        Cards.Add(card);
    }

    public void RemoveCard(Card card)
    {
        if (!Cards.Contains(card))
            throw new InvalidOperationException($"Hand does not contain card {card}.");

        Cards.Add(card);
    }
}

5. Dealer to handle the CardDeck and issue Card to a Hand:
C#
public class Dealer
{
    public Dealer(CardDeck deck)
        => Deck = deck;

    public CardDeck Deck { get; }

    public void DealCard(Hand hand)
        => hand.AddCard(Deck.DrawTopCard());
}

NOTE: I have not added support for the Joker as BlackJAck does not use one.

Now we can test the Deck methods: Shuffle and Sort:
C#
CardDeck cardDeck = new CardDeck();
DumpDeck("Created Deck");

Shuffle();
TestSortBy();

Shuffle();
TestSortBy(CardSortType.SuitThenKind);

Shuffle();
TestSortBy(CardSortType.KindThenSuit);

Shuffle();
TestSortBy(CardSortType.SuitOnly);

Shuffle();
TestSortBy(CardSortType.KindOnly);

Hand myHand = new("Player 1");
Dealer theDealer = new Dealer(cardDeck);

theDealer.DealCard(myHand);
theDealer.DealCard(myHand);

DumpHand(myHand);

void Shuffle()
{
    cardDeck.Shuffle();
    DumpDeck("Shuffled Deck");
}

void TestSortBy(CardSortType? sortType = null)
{
    if (sortType == null)
        cardDeck.Sort();
    else
        cardDeck.Sort(new CardSorter { SortBy = (CardSortType)sortType });

    DumpDeck($"Sorted By: {(sortType != null ? sortType.ToString() : "default")}");
}

void DumpDeck(string title)
{
    Console.WriteLine($"--- {title} ---");
    
    foreach (Card card in cardDeck.Cards)
        Console.WriteLine(card);
    
    Console.WriteLine();
}

void DumpHand(Hand hand)
{
    Console.WriteLine($"--- Player: {hand.Name} ---");
    
    foreach (Card card in hand.Cards)
        Console.WriteLine(card);
    
    Console.WriteLine();
}


Hope this helps!
 
Share this answer
 
v3
Classes are the computer representation of things in the real world, and - just like in the real world - you need instances of a class in order to use them. That probably doesn't make a lot of sense right at the moment, or have any relevance to your error message - but bear with me ...
Instances are all around us, so let's ignore computers for a moment and talk about cars.

This car; that car; your car; my car. We all know what they mean: they identify a specific vehicle out of the "phase space" of "all potential cars" that I could be discussing. When I say "I drove my car to the shops" you envisage me at the wheel of a large grey Mercedes (or you would if you knew me) rather than the compact blue Ford you normally drive. "My car" here serves to indicate specifically which car I am talking about without confusion.

"My car" references an instance of a car, while "Your car" references a different instance. And instances can be "shared": if my wife and I have just one car which we both drive, we can refer to it as "Our car", "My car", and "Her car" without confusion. The references identify the same instance.

And we all know that cars are different objects: If you put your mobile in the glove box of "your car", you wouldn't expect to open the glove box of "my car" and find it. But...if my wife puts her mobile in the glove box of "her car" then I can find it for her by looking in the glove box of "my car". Same instance, two references.

And we know that you need an instance of a car to do anything: you can't ask the question "What colour is a car?" because not all cars are the same colour. We can ask "How many wheels has a car?" because all cars have four wheels - if they had less, they would be a trike or bike!

When you take this back to computers, you find you have a similar situation.

Suppose we have a simple little class:
C#
public class Car
    {
    #region Properties
    /// <summary>
    /// Who made the car
    /// </summary>
    public string Manufacturer { get; private set; }
    /// <summary>
    /// Model of car
    /// </summary>
    public string Model { get; private set; }
    /// <summary>
    /// Colour of the vehicle
    /// </summary>
    public Color Colour { get; private set; }
    /// <summary>
    /// How many wheels has the vehicle?
    /// </summary>
    public static int NumberOfWheels { get { return 4; } }
    #endregion

    #region Constructors
    /// <summary>
    /// Default constructor
    /// </summary>
    public Car(string manufacturer, string model, Color colour)
        {
        Manufacturer = manufacturer;
        Model = model;
        Colour = colour;
        }
    #endregion

    #region Overrides
    /// <summary>
    /// Returns a human readable version of the vehicle.
    /// </summary>
    /// <returns></returns>
    public override string ToString()
        {
        return $"{Manufacturer} {Model} ({Colour})";
        }
    #endregion
    }

Now we can create something that describes my car:
C#
Car myCar = new Car("Mercedes", "B180", Color.MountainGrey);

This line of code does several things:

It creates a variable called "myCar" which can hold a Car (or a class derived from Car).
It creates a new instance of a Car, gives it the information that identifies it as my car.
The instance is assigned to the variable.
We can create a different car:
C#
Car gillsCar = new Car("Volkswagen", "Golf", Color.Orange);

And it's pretty obvious that that is a separate vehicle!

So when we want to know what colour a vehicle is, we "ask" the appropriate vehicle:
C#
Console.WriteLine($"I drive a {myCar.Colour} car.");
Console.WriteLine($"Gill drives a {gillsCar.Colour} car.");

And we will get the right data:
I drive a Mountain Grey car.
Gill drives a Orange car.


But we can ask about wheels by querying the Car class directly:
C#
Console.WriteLine($"A car has {Car.NumberOfWheels}.");
And get
A car has 4 wheels.


If I try to ask "What colour is a Car?" then the code looks like this:
C#
Console.WriteLine($"A car is coloured {Car.Colour}.");
And I get an error:
Error
An object reference is required for the non-static field, method, or property 'Car.Colour'
Because not all cars are the same colour!

And now we go back to your code where you have the same error: you need to specify exactly which deck of cards you are trying to shuffle, because not all decks are the same: two blackjack tables in the same casino will each be drawing from their own deck which do not interact!

So your code needs to declare a variable to hold a deck of cards, and use that to shuffle and deal from.
I can't write that code for you - I can't see enough of your project to do that - but hopefully now you understand a little better what you are trying to acheive, and how you need to achieve it. Make sense?
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900