Design and Creating a black Jack game

T

Tony Johansson

Hello!

I'm in the progress of creating a Black Jack game. I have created these
classes.
Game, Deck, Card, Player and Hand. A Game contains a Deck and a Deck
contains an array of Cards.
A Game also contains a List<Player> and a player contains a hand which is a
List of Cards.
None of these Game,Deck,Card,Player and Hand is instansiated in The MainGUI.
There is a second class called GameManager that is instansiating the Game
and this GameManager is instansiated in the MainGUI

The mainGUI contains a DataGridView and some buttons and some user controls
where each user control represent each player that will participate in this
Black jack game. We call this user control PlayerGUI.
The user control(PlayerGUI) that represent the player contains a TextBox for
the player name and some labels and two Buttons and a panel where each drawn
card should be displayed. The Card that is to be displayed in the panel of
the PlayerGUI is also a user control called CardGUI.

At the beginning of the game I create the PlayerGUI and place it in the form
and enter the name in the DataGridView cell where the column is called name
and when this cell go out of focus the TextBox in the PlayerGUI gets updated
with the same name.
I have a binding between the List<Player> and the DataGridView DataDource
and the List<Player> is placed in the Game class as I mentioned previously.

The MainGUI have four Buttons(NewPlayer, StartGame, CalculateWinner and
NewGame)
Now when I click on the StartGame I want to place some cards which
represented by the CardGUI in the Panel
of the PlayerGUI.

Now to my question which class should be responsible to deal the initial two
cards to each player where the croupier is also a player ?

It's only the MainGUI that know about the PlayerGUI so first I thought
MainGUI class would be a good choice
but I don't think that is good design.

The Game class would otherwise be a good choice but I don't have a reference
to the playerGUI where the CardGUI should be placed ?

So assume I choose to place the Deal method in the Game class how do I best
get access to all PlayerGUI that is placed in the MainGUI form class ?

//Tony
 
T

Tony Johansson

Tony Johansson said:
Hello!

I'm in the progress of creating a Black Jack game. I have created these
classes.
Game, Deck, Card, Player and Hand. A Game contains a Deck and a Deck
contains an array of Cards.
A Game also contains a List<Player> and a player contains a hand which is
a List of Cards.
None of these Game,Deck,Card,Player and Hand is instansiated in The
MainGUI.
There is a second class called GameManager that is instansiating the Game
and this GameManager is instansiated in the MainGUI

The mainGUI contains a DataGridView and some buttons and some user
controls where each user control represent each player that will
participate in this Black jack game. We call this user control PlayerGUI.
The user control(PlayerGUI) that represent the player contains a TextBox
for the player name and some labels and two Buttons and a panel where each
drawn card should be displayed. The Card that is to be displayed in the
panel of the PlayerGUI is also a user control called CardGUI.

At the beginning of the game I create the PlayerGUI and place it in the
form and enter the name in the DataGridView cell where the column is
called name and when this cell go out of focus the TextBox in the
PlayerGUI gets updated with the same name.
I have a binding between the List<Player> and the DataGridView DataDource
and the List<Player> is placed in the Game class as I mentioned
previously.

The MainGUI have four Buttons(NewPlayer, StartGame, CalculateWinner and
NewGame)
Now when I click on the StartGame I want to place some cards which
represented by the CardGUI in the Panel
of the PlayerGUI.

Now to my question which class should be responsible to deal the initial
two cards to each player where the croupier is also a player ?

It's only the MainGUI that know about the PlayerGUI so first I thought
MainGUI class would be a good choice
but I don't think that is good design.

The Game class would otherwise be a good choice but I don't have a
reference to the playerGUI where the CardGUI should be placed ?

So assume I choose to place the Deal method in the Game class how do I
best get access to all PlayerGUI that is placed in the MainGUI form class
?

//Tony

When I click on the GameStart I can pass pnlPlayers.Controls as an argument.
This pnlPlayers.Controls holds the PlayerGUI that is of type
System.Windows.Forms.ControlCollection but is it acceptable oop design to
use Windows.Forms in so to speak business classes like the Game class and
GameManager ?

//Tony
 
T

Tony Johansson

Peter Duniho said:
[...]
Now to my question which class should be responsible to deal the initial
two
cards to each player where the croupier is also a player ?

First suggestion: do not post details about your program that have nothing
to do with your question. There was a lot of text to read there, much of
which was irrelevant and just wastes the time of people reading your post.
It's only the MainGUI that know about the PlayerGUI so first I thought
MainGUI class would be a good choice
but I don't think that is good design.

From your description, it seems that you have intermingled your GUI and
game modeling code more than would normally be considered desirable. This
will generally lead to difficult design problems.
The Game class would otherwise be a good choice but I don't have a
reference
to the playerGUI where the CardGUI should be placed ?

Inasmuch as your Game class is essentially a controller for the model,
encapsulating the game mechanics implementation for the program, it seems
to me that of the types you've described so far, the Game class best fits
your card-dealing logic.

The ".GUI" types really shouldn't care about the game mechanics at all.
They should simply present the current state of other objects to the user.
The Game class, when dealing cards, will directly affect only the Deck and
Player objects (the Deck object will lose Card instances, while each
Player object will gain them). The ".GUI" objects then should respond to
changes in state of the other objects (e.g. be subscribed to an event that
is raised when the composition of a deck or hand of cards changes).
So assume I choose to place the Deal method in the Game class how do I
best
get access to all PlayerGUI that is placed in the MainGUI form class ?

You don't. The Game class shouldn't know anything at all about the
PlayerGUI class, nor even the MainGUI class. You should have some
top-level "controller" type that coordinates connections/data-flow between
the GUI classes and the model classes, such as the Game class. Updates to
the ".GUI" objects will occur naturally from whatever mechanism you choose
for that design goal (e.g. events).

Pete

Here is a method InitialDeal that is responsible to deal two cards to each
player.
pnlPlayer is a Panel type.
gm is an instance of a class called GameManager.
This method is located in the MainGUI class.
I just want your opinion if this kind of design of a method in the MainGUI
is somewhat sensible if we look at the OOP.
I have tried to use some kind of layer arcitecture and put things here that
I mean must be here.
I mean I must have some sort of logic here.

private void InitialDeal()
{
// Here I fetch all controls that is called PlayerGUI
Control[] ctrl = this.pnlPlayers.Controls.Find(PlayerGUI, false);
string cardRank;
string image;

// Deal two cards to each player
for (int cardNr = 0; cardNr < InitialDealRound; cardNr++)
{

//Here we have all the players that is participating in the
Black jack game
for (int playerNr = 0; playerNr < ctrl.Length; playerNr++)
{
// Get the card for the specified Player and the cardnr
Card card = gm.GetPlayerCard(playerNr, cardNr);

// loop through all the PlayerGUI until you find the right
name
for (int i = 0; i < pnlPlayers.Controls.Count; i++)
{

//Check if this PlayerGUI contains the right name
PlayerGUI pg = ctrl as PlayerGUI;
if (pg.PlayerName == gm.Players[playerNr].Name)
{
string imagePath =
Path.Combine(Environment.CurrentDirectory, @"..\..\Images\" + card.Suit+
".ico");

//crete the usercontrol CardGUI and place it in the
PlayerGUI panel
CardGUI cg = new CardGUI(imagePath, card.rankSymbol);

int xPos = (cardNr % 2) * cg.Width;
cg.Location = new Point(xPos, 0);
pg.AddCard(cg);
break;
}
}
}
}
dgvAllPlayers.Refresh();
}
//Tony
 
T

Tony Johansson

Peter Duniho said:
Those first two sentences by themselves tell me your design is incorrect.
A method that deals cards should have no reason whatsoever to know about a
Panel instance. It should only be interacting with a non-GUI type that
manages the state of the game.


It is not sensible. Again, perhaps if you ignore the bigger picture and
focus _only_ on the very abstract object-oriented question, you could
argue in favor of the design. But it's not enough to abstract things in
an object-oriented way; you have to abstract things in a way that is
proper in all the ways that matter.

Using GUI objects to maintain or even access/reveal the state of the
non-GUI aspects of your program is poor design. It causes your types to
be too involved with matters that aren't relevant to the primary purpose
of those types.

You keep asking about "OOP" but IMHO that's not really the important
context for this line of questioning.

From a design point of view, your question is sort of like asking "I am
designing a new animal; here I have followed the usual technique of
providing pulmonary, circulatory, lymphatic, muscle, and nervous systems.
Even though I've put the eyeballs on the soles of the feet, doesn't the
fact that I've got all the basic networked systems in the body mean that
my animal is correct?"

OOP is not an end unto itself. It's just a single piece of a larger
process for making a good program. It's important to have a good OOP
foundation on which the rest of your program is built, but it's not
sufficient to concern yourself only with the object-oriented nature of the
code. You have to look at the big picture.

Pete


From the MainGUI I call a method called Start this is located in the
GameManager. This GameManager was instansiated in MainGUI. From GameManager
I call NewDeal that is located in the Game class and here I deal two card to
each player to put in the hand of the player
What I want now is to put the cards that is stored in the hand of each
player in the PlayerGUI.
What is the best way to establish that. I mean If I use this
NotifyPropertyChanged when I added a new card in the hand of a Player I
can't subscribe to this event from the MainGUI class because I don't have a
reference to the hand class it's only the Player class that has a reference
to the hand class.

It seems impossible to make the GUI subscribe to some sort of event so they
can update the GUI with cards.
So the only option seems to read the hand for each player from the GUI
through GameManager and the Game class

//Tony
 
T

Tony Johansson

Peter Duniho said:
The best way to establish that is for the PlayerGUI class to subscribe to
an event on the Player class that is raised when the hand of the player
changes. Then the PlayerGUI will update itself based on the new contents
of the player's hand.


You can either expose the Hand class so that the GUI classes can see it,
or you can write a new event in the Player class that essentially
delegates the event to the Hand class, by having the Player class
subscribe to the Hand class's event and then raising its own when the Hand
class's event is raised.

Without a proper code example, I don't really understand how the PlayerGUI
can even show the cards in the player's hand if it doesn't know about the
Hand class. But whatever: the bottom line is, if you're going to follow
your current design, just put the event wherever the GUI types are
currently finding out about the cards in the hand already.


It's programming. Nothing is impossible, though lots of choices are
ill-advised. Sometimes the only available choices are in fact
ill-advised, which then means you've messed up the overall design. In
that case, you can either go with fixing the code in an ill-advised way,
or you have to go back and fix the design first, so that you have options
that are not ill-advised.

Pete

Here is how my classes talk to each other and I hope it would be possible to
subscribe to the event PropertyChanged
that is raised in the Hand class when a new card is added to the hand of a
Player.
I hope that you can give me some advise how I can do that.

This MainGUI class which is called CardGameTester has a reference two these
two class library CardGameClassLib and CardGameControlLib

CardGameClassLib contains these classes Game,Deck,Card,PLayer and Hand
CardGameControlLib contains these classes PlayerGUI and CardGUI which is
user controls

public partial class CardGameTester : Form
{
private BindingSource bindingSource = new BindingSource();
private GameManager gm = new GameManager();
....

private void BtnStartGame_Click(object sender, EventArgs e)
{
gm.Start();
}
....
}



public class GameManager
{
private Game game = new Game();

public void Start()
{
game.NewDeal();
}
}


public class Game
{
const int InitialDealRound = 2;
private int currentPlayer;
private Deck deck = new Deck();
private int nrOfPlayers;
private List<Player> players = new List<Player>();

public void NewDeal()
{
nrOfPlayers = players.Count;

deck.Shuffle();

for (int cardNr = 0; cardNr < InitialDealRound; cardNr++)
{
for (int playerNr = 0; playerNr < nrOfPlayers; playerNr++)
{
players[playerNr].DrawCard(deck.GetNextCard());
}
}
}
}

public class Deck
{
const int MaxNumOfCardsPerDeck = 52;
private Card[] cards;
private int currentPosition = 0 ;

public Card GetNextCard()
{
if (currentPosition == cards.Length)
{
currentPosition = 0;
Shuffle();
}
return cards[currentPosition++].Clone() as Card;
}
....
}

public class Player
{
private Hand hand = new Hand();
private int playerID;
private int losts;
private string name;
private int wins;
private int sum;
private int currentSum;

public void DrawCard(Card card)
{
hand.AddCard(card);
}
}

public class Hand : INotifyPropertyChanged,ICloneable
{
const int LuckyNumber = 21;
private List<Card> cards = new List<Card>();
public event PropertyChangedEventHandler PropertyChanged;

public void AddCard(Card card)
{
cards.Add(card);
NotifyPropertyChanged("CardAdded");
}

private void NotifyPropertyChanged(string info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
}

//Tony
 
T

Tony Johansson

Forget this. I found a solution that I can publish the event in the game
class and subscribe to this event in the GUI class and it
works fine.

//Tony
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top