This code randomizes 52 cards and puts 13 each in 4 box of text with every click. I got the general idea of how it worked, but I need help clearing some confusion or understanding how it worked. I put bold comments on the ones I am not too sure about.
namespace Cards
{
enum Value { Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten, Jack, Queen, King, Ace}
}
namespace Cards
{
enum Suit { Clubs, Diamonds, Hearts, Spades }
}
namespace Cards
{
class PlayingCard
{
private readonly Suit suit;
private readonly Value value;
public PlayingCard(Suit s, Value v)
{
this.suit = s;
this.value = v;
}
public override string ToString()
{
string result = string.Format("{0} of {1}", this.value, this.suit);
return result;
}
public Suit CardSuit() // **Not sure why this is here. Maybe for future use?**
{
return this.suit;
}
public Value CardValue() // **Same as above**
{
return this.value;
}
}
}
namespace Cards
{
using System;
using System.Collections;
class Pack // **Data Access Layer?**
{
public const int NumSuits = 4;
public const int CardsPerSuit = 13;
private PlayingCard[,] cardPack;
private Random randomCardSelector = new Random();
public Pack() //**Storing all elements**
{
this.cardPack = new PlayingCard[NumSuits, CardsPerSuit]; //
for (Suit suit = Suit.Clubs; suit <= Suit.Spades; suit++) //
{
for (Value value = Value.Two; value <= Value.Ace; value++)
{
this.cardPack[(int)suit, (int)value] = new PlayingCard(suit, value);
}
}
}
public PlayingCard DealCardFromPack() // **Purpose: To dealing unique cards**
{
Suit suit = (Suit)randomCardSelector.Next(NumSuits); // **picks random 0-3 from Suit**
while (this.IsSuitEmpty(suit)) // **Purpose: Checks if empty but don't know how it works**
{
suit = (Suit)randomCardSelector.Next(NumSuits);
}
Value value = (Value)randomCardSelector.Next(CardsPerSuit);
while (this.IsCardAlreadyDealt(suit, value)) // ?
{
value = (Value)randomCardSelector.Next(CardsPerSuit);
}
PlayingCard card = this.cardPack[(int)suit, (int)value];
this.cardPack[(int)suit, (int)value] = null; // **sets the current element to null so it isn't reused.**
return card;
}
private bool IsSuitEmpty(Suit suit) // **checks if empty**
{
bool result = true;
for (Value value = Value.Two; value <= Value.Ace; value++) //**Checks Null or not**
{
if(!IsCardAlreadyDealt(suit, value))
{
result = false;
break;
}
}
return result;
}
private bool IsCardAlreadyDealt(Suit suit, Value value) //**returns current element null?**
{
return (this.cardPack[(int)suit, (int)value] == null);
}
}
}
namespace Cards
{
using System;
using System.Collections;
class Hand // **Business layer?**
{
public const int HandSize = 13;
private PlayingCard[] cards = new PlayingCard[HandSize]; // **single array? Thought it had to be 2 because of 2 parameters?**
private int playingCardCount = 0;
public void AddCardToHand(PlayingCard cardDealt)//**Confusion when class used as variable**
{
if (this.playingCardCount >= HandSize)
{
throw new ArgumentException("Too many cards");
}
this.cards[this.playingCardCount] = cardDealt; //**Confused...cardDealt value going in card[]? How does that work..**
this.playingCardCount++;//**incrementing, how is this helpful**
}
public override string ToString() //to show all 13 cards in hand
{
string result = "";
foreach (PlayingCard card in this.cards)
{
result += card.ToString() + "\n";
}
return result;
}
}
}
namespace Cards
{
public partial class Game : Window
{
public const int NumHands = 4;
private Pack pack = null;
private Hand[] hands = {new Hand(), new Hand(), new Hand(), new Hand()}; //**Creates 4 different list all single array?**
public Game()
{
InitializeComponent();
}
private void dealClick(object sender, RoutedEventArgs e)
{
try
{
pack = new Pack();
for (int handNum = 0; handNum < NumHands; handNum++) //
{
hands[handNum] = new Hand();
for (int numCards = 0; numCards < Hand.HandSize; numCards++)
{
PlayingCard cardDealt = pack.DealCardFromPack(); //**Deals 13 random cards into each array. Don't understand how it worked though.**
hands[handNum].AddCardToHand(cardDealt);
}
}
north.Text = hands[0].ToString();
south.Text = hands[1].ToString();
east.Text = hands[2].ToString();
west.Text = hands[3].ToString();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
}
}
PlayingCard:
This looks like a business model, nothing to do with data access. In fact, I don’t see any data persistence (like a database) being used in the code at all, so this application doesn’t have a data access layer.
Correct. This makes the value “immutable” in that it can’t be changed once the object is constructed. Note that this value is set in (and only in) the class’ constructor. So to have a different
suitone needs to construct a different instance of the class (a different object, as it were).Not really. This is the constructor for the class. Any time a new instance of the class is created (for example,
var card = new PlayingCard(someSuit, someValue)), this method executes to construct that instance.This is a method to get the value of the current
Suitfor that card. So something using the card can see what suit it is. Note that the value it’s returning isprivateso it can’t otherwise be read from outside the class. (I disagree with this implementation and would prefer a property instead of a method, but that’s another subject entirely.)Pack:
Nope, same as before. These are models. I’ll get to that in a bit.
Constructor again, same as before.
Yes. This is a logical method to have on a
Packobject. One can reasonably expect that aPackcan be used to dealPlayingCards. That is, they can be extracted from thePack. So that’s what this method is for.Yup, chooses a random
Suitfrom the given enumeration of knownSuits.Well, a pack doesn’t have an infinite number of cards. Every time one is removed, it’s deleted from the class that’s holding the cards (the
Pack). So it can’t very well deal from a suit for which it no longer has cards. Thus, this checks to see if there are still cards left in the suit before trying to deal one.Yup, this is related to the previous part. When a card is dealt, it’s removed. So this “deletes” it from the
Pack.This is a kind of helper method within the class. The method which deals out the cards needs to check if the suit is empty, so this method was written to make that check. (Rather than have all of the code in one big method, which would be poor design.)
This is another helper method. When dealing cards, one can’t deal a card that’s already been dealt. So this checks for that. So basically, the larger method which uses these methods is saying: “While randomly looking at suits, I need a suit that still has cards. While randomly looking at cards in that suit, I need a card that’s still in the deck. Now remove that card from the deck.”
Hand:
Kind of. Sort of. It’s another model. I’ll get to that in a second.
What 2 parameters? It’s an array of cards. Each
Handis basically a collection of cards. This stores references to those cards.I’m not sure what you’re asking in the comment. The purpose of this method is to add a card to the hand. So a reference to a card is passed to the method, and the method adds it to the current hand.
In this case,
cardDealtis the card that was given to theHandto be added. It has nothing to do with the “dealt” concept in the previous class. It’s just the name of the variable. What this line is doing is adding that card to the array of cards in theHand.The hand is now larger by one card. So if you added, say, the third card to the hand, it would be added as
this.cards[2]. Adding another card to the hand after that needs to go inthis.cards[3], otherwise it would replace an existing card, which isn’t the desired effect.Correct, this method is just to print out what’s currently in the
Hand.Conclusion:
Ok, now that we’ve gone through that exercise (and feel free to ask for clarification), let’s talk for a moment about what a “model” is. It’s kind of a business layer in that it’s a “business object.” That is, it’s an object which encapsulates a business concept.
In the case of this application, there are three concrete concepts which represent the “business” of dealing cards to a hand. These are:
Each model has the responsibility to internally maintain its business logic. This is done with its internal variables, properties, methods, etc. Things like
DealCardFromDeckare real-world concepts of how the business works which are encoded into the models. The other models don’t care how that model implements that business logic, they just know that one can deal a card from a deck. (This is part of the model’s externally-visible interface to other models.)The business logic (business layer, if you will, although this code snipped doesn’t really have “layers” per se) is seen in how the models interact with one another. At its simplest, my list of the three models above basically describes how they interact. The code is just an implementation of that logic.