Going through Head First C#'s Chapter 8: Enums and Collections, I learned about List<T>
, as well as IComparable<T>
and IComparer<T>
. One exercise near the end asked to make a program to draw cards at random, then sort them.
I wanted to go the extra mile and make a fully usable, realistic card deck (their solution just picked 5 values at random from 2 enums, which could result in drawing the same card twice).
Any and all advice is welcome, albeit please understand that I have yet to learn LINQ in a coming chapter, so if you suggest to use it for something please at least explain why/advantages over vanilla C#.
I'm not including the using
statement, they are the default ones that Visual Studio adds when creating a C# console project.
Kind
enum Kind
{
Ace,
Two,
Three,
Four,
Five,
Six,
Seven,
Eight,
Nine,
Ten,
Jack,
Queen,
King,
}
Suit
enum Suit
{
Clubs,
Diamonds,
Hearts,
Spades,
}
Card
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)
{
if (Suit > other.Suit)
{
return 1;
}
if (Suit < other.Suit)
{
return -1;
}
return Kind > other.Kind ? 1 : -1;
}
public override string ToString()
{
return $"{Kind} of {Suit}";
}
}
CardDeck
class CardDeck
{
public List<Card> Cards;
public CardDeck()
{
Cards = new List<Card>();
int numSuits = Enum.GetNames(typeof(Suit)).Length;
int numKinds = Enum.GetNames(typeof(Kind)).Length;
for (int suit = 0; suit < numSuits; suit++)
{
for (int kind = 0; kind < numKinds; kind++)
{
Cards.Add(new Card((Kind)kind, (Suit)suit));
}
}
}
public int CountCardsInDeck => Cards.Count;
public Card DrawTopCard()
{
Card drawnCard = Cards[0];
Cards.RemoveAt(0);
return drawnCard;
}
public Card DrawBottomCard()
{
int lastCardIndex = CountCardsInDeck - 1;
Card drawnCard = Cards[lastCardIndex];
Cards.RemoveAt(lastCardIndex);
return drawnCard;
}
public Card DrawRandomCard()
{
Random random = new Random();
int randomCardIndex = random.Next(CountCardsInDeck);
Card drawnCard = Cards[randomCardIndex];
Cards.RemoveAt(randomCardIndex);
return drawnCard;
}
public void AddCardOnTop(Card card)
{
if (!Cards.Contains(card))
{
Cards[0] = card;
return;
}
throw new InvalidOperationException($"Deck already contains card {card}.");
}
public void AddCardOnBottom(Card card)
{
if (!Cards.Contains(card))
{
Cards.Add(card);
return;
}
throw new InvalidOperationException($"Deck already contains card {card}.");
}
public void AddCardAtRandom(Card card)
{
if (!Cards.Contains(card))
{
Random random = new Random();
Cards[random.Next(CountCardsInDeck)] = card;
return;
}
throw new InvalidOperationException($"Deck already contains card {card}.");
}
public void Shuffle()
{
// Fisher-Yates shuffle method
Random random = new Random();
int n = CountCardsInDeck;
while (n > 1)
{
n--;
int k = random.Next(n + 1);
Card randomCard = Cards[k];
Cards[k] = Cards[n];
Cards[n] = randomCard;
}
}
public void Sort() => Cards.Sort();
public void Sort(IComparer<Card> comparer) => Cards.Sort(comparer);
public void WriteToConsole()
{
foreach (Card card in Cards)
{
Console.WriteLine(card);
}
}
}
CardOrderMethod
enum CardOrderMethod
{
SuitThenKind,
KindThenSuit,
}
CardSorter
class CardSorter : IComparer<Card>
{
public CardOrderMethod SortBy = CardOrderMethod.SuitThenKind;
public int Compare(Card x, Card y)
{
if (SortBy == CardOrderMethod.SuitThenKind)
{
if (x.Suit > y.Suit)
{
return 1;
}
if (x.Suit < y.Suit)
{
return -1;
}
return x.Kind > y.Kind ? 1 : -1;
}
if (SortBy == CardOrderMethod.KindThenSuit)
{
if (x.Kind > y.Kind)
{
return 1;
}
if (x.Kind < y.Kind)
{
return -1;
}
return x.Suit > y.Suit ? 1 : -1;
}
throw new NotImplementedException($"CardOrderMethod {SortBy} is not implemented.");
}
}
Program
class Program
{
static void Main(string[] args)
{
CardDeck cardDeck = new CardDeck();
cardDeck.Shuffle();
Console.WriteLine("---Shuffled deck---");
cardDeck.WriteToConsole();
CardSorter sorter = new CardSorter
{
SortBy = CardOrderMethod.SuitThenKind
};
cardDeck.Sort(sorter);
Console.WriteLine("---Sorted deck: SuitThenKind---");
cardDeck.WriteToConsole();
cardDeck.Shuffle();
sorter.SortBy = CardOrderMethod.KindThenSuit;
cardDeck.Sort(sorter);
Console.WriteLine("---Sorted deck: Kind Then Suit---");
cardDeck.WriteToConsole();
// Keep console open until a key is pressed
Console.ReadKey();
}
}
Ace
is ranked belowTwo
in the enum? Most games rank theAce
as the highest card. \$\endgroup\$ – jpmc26 Jul 7 '19 at 3:09