So this is something I have seen a number of times on StackOverflow, so I thought I would spend some time while I was on a ferry creating a solution for. So what we have is a standard deck of cards, 52 cards (no jokers), 4 suits (Clubs, Diamonds, Hearts and Spades) each with 13 cards (ace through to king). In this post I will go through the code that has been produced and at the bottom of the post there is a download link for the entire solution, unit tests and all.
Source: http://www.leadersinstitute.com/wp-content/uploads/2011/02/playing-cards.jpg
Suit Enum
namespace Cards.Domain.Standard
{
public enum Suit
{
Club = 1,
Diamond = 2,
Heart = 3,
Spades = 4,
}
}
Card Number Enum
I decided to use an enum for the card number as well as for the suit as rather than having numbers directly for the card number I could have an appropriate value, which could be given an Attribute to allow for further information to be associated with it.
namespace Cards.Domain.Standard
{
public enum CardNumber
{
Ace = 1,
Two = 2,
Three = 3,
Four = 4,
Five = 5,
Six = 6,
Seven = 7,
Eight = 8,
Nine = 9,
Ten = 10,
Jack = 11,
Queen = 12,
King = 13,
}
}
Card class
The card class is extremely simple, it is just two properties, one for the suit and one for the card number.
namespace Cards.Domain.Standard
{
public class Card
{
public Suit Suit { get; set; }
public CardNumber CardNumber { get; set; }
}
}
Deck class
The Deck class is where most of the interesting stuff happens.
using System;
using System.Collections.Generic;
using System.Linq;
namespace Cards.Domain.Standard
{
public class Deck
{
public Deck()
{
Reset();
}
public List<Card> Cards { get; set; }
public void Reset()
{
Cards = Enumerable.Range(1, 4)
.SelectMany(s => Enumerable.Range(1, 13)
.Select(c => new Card()
{
Suit = (Suit)s,
CardNumber = (CardNumber)c
}
)
)
.ToList();
}
public void Shuffle()
{
Cards = Cards.OrderBy(c => Guid.NewGuid())
.ToList();
}
public Card TakeCard()
{
var card = Cards.FirstOrDefault();
Cards.Remove(card);
return card;
}
public IEnumerable<Card> TakeCards(int numberOfCards)
{
var cards = Cards.Take(numberOfCards);
var takeCards = cards as Card[] ?? cards.ToArray();
Cards.RemoveAll(takeCards.Contains);
return takeCards;
}
}
}
Reset
This method uses a nice piece of LINQ to generate all the required cards for the standard 52 card deck and populate the Cards property of the deck. This method is called by the constructor to set up the Deck class.
Shuffle
When the cards are generated they are created in an ordered fashion, this method orders all the cards randomly again using LINQ.
TakeCard
This method as the name suggests takes a card from the Deck. It will get the next Card in the Deck and return it, removing it from the Cards collection so it can’t be taken again. If there are no more Cards in the Deck then this method will return a null.
TakeCards
This method is like TakeCard although it allows for the user to take more than one Card. I made a design decision to return the requested amount or the remainder of the Cards in the Deck, so if the user asks for five Cards but there are only three left, then it will return those three, although some might say that as we are not able to correctly fulfil the request we should be throw an exception.
Deck of Cards usage
The deck of cards code can be used to implement your own card game software, a solitaire, poker game etc. the code it pretty simple and well defined so shouldn’t require much in the way of adjustments for any standard 52 card deck game. If you want to add Jokers then that will require a little more work but nothing too major (I’m just not too sure about their usage in games so I thought I would leave them out).
Anyway the solution that I produced for the deck of cards is available for download here (Deck of Cards in C#)