Sign in to follow this  
Gohalien

[C#] Guess The Number (My first game code)

Recommended Posts

POKER GAME IS ON HOLD, I STARTED WITH A MORE SIMPLE GAME Learning C# making the game: GuessTheNumber ----- Hello people, I am trying to make an online poker game to learn more about game dev, sockets, svn and in a future directX. I have current experience using C# with mysql. Since I learned a lot from this forum, I will be sharing my experience developing this game. First of all, since I am using already http://www.codeproject.com/KB/IP/ChatAsynchTCPSockets.aspx?msg=2375668#xx2375668xx example about Asynch TCP Sockets (Client <-> Server) comunication I started with the Card class. What I have done is how to generate a card and check if this card isnt already in game:
    class Deck
    {
        public DataTable IngameCards = new DataTable();
        private int[] number = new int[13] { 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 }; //J=11, Q=12, K=13, A=14
        private string[] color = new string[4] { "H", "S", "C", "D" }; //Heart, Spade, Club, Diamond
        public Deck()
        {
            IngameCards.Columns.Add("NUMBER", typeof(Int32));
            IngameCards.Columns.Add("COLOR", typeof(String));
        }
        public object[] GenerateCard()
        {
            object[] card_generated = new object[2];
            bool exist = false; //Card "already ingame" flag
            Random random = new Random();
            card_generated[0] = number[random.Next(13)];
            card_generated[1] = color[random.Next(4)];
            foreach (DataRow row in IngameCards.Rows) //Now we must check if that card is already in game (need optimization)
            {
                if (!exist)
                {
                    if (((Int32)row[0] == (Int32)card_generated[0]) && ((String)row[1] == (String)card_generated[1]))
                    {
                        exist = true; //Card is in already in game
                        break; //We dont need to check the other cards in game.
                    }
                }
            }
            if (!exist)
            {
                IngameCards.Rows.Add(card_generated); //We add the generated card to the IngameCards datatable
            }
            else
            {
                card_generated = GenerateCard(); //We seek a new card.
            }
            return card_generated;
        }
        public void ClearDeck()
        {
            IngameCards.Clear();
        }
    }





Now if we need to deal cards, we can check if the cards are not repeating...
        private void button1_Click(object sender, EventArgs e)
        {
            Deck TableOneDeck = new Deck();
            TableOneDeck.ClearDeck();
            for (int i=0; i < 10; i++)
            {
                this.dataGridView1.DataSource = TableOneDeck.IngameCards;
                object[] Player1Card1 = TableOneDeck.GenerateCard();
                object[] Player1Card2 = TableOneDeck.GenerateCard();
                this.textBox1.Text += string.Format("Card 1: {0}{1} Card 2: {2}{3}\r\n", Player1Card1[0], Player1Card1[1], Player1Card2[0], Player1Card2[1]);
            }
        }





Trust me, they dont repeat ^^ [Edited by - Gohalien on January 9, 2008 3:40:09 PM]

Share this post


Link to post
Share on other sites
Made a better logic to create & deal cards:

class Deck
{
public DataTable dt_Deck = new DataTable();
private int[] number = new int[13] { 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 }; //J=11, Q=12, K=13, A=14
private string[] color = new string[4] { "H", "S", "C", "D" }; //Heart, Spade, Club, Diamond
public Deck()
{
dt_Deck.Columns.Add("NUMBER", typeof(Int32));
dt_Deck.Columns.Add("COLOR", typeof(String));
CreateCards();
}
private void CreateCards()
{
//Here we create the 52 cards
object[] card_generated = new object[2];
for (int i = 0; i &lt; 13; i++)
{
for (int ii = 0; ii &lt; 4; ii++)
{
card_generated[0] = number[i];
card_generated[1] = color[ii];
dt_Deck.Rows.Add(card_generated); //We add the card to the Deck datatable
}
}
}
public object[] DealCard()
{
//Note: If we don't include the Thread.Sleep, the cards are dealed so fast that the "random" function isn't "really random"
Random random = new Random();
object[] card_selected = new object[2];
if (dt_Deck.Rows.Count &gt; 0) //Here checks if our deck datatable have cards
{
int deck_row = random.Next(dt_Deck.Rows.Count);
card_selected[0] = dt_Deck.Rows[deck_row]["NUMBER"];
card_selected[1] = dt_Deck.Rows[deck_row]["COLOR"];
dt_Deck.Rows.RemoveAt(deck_row); //Delete the dealed card from the deck
}
Thread.Sleep(random.Next(1,10)); //Randomly sleep the thread to make the "random" more... ramdom -.-
return card_selected;
}
public void NewDeck()
{
dt_Deck.Clear();
CreateCards();
}
[/source lang="c#"]
Now in a form...

Deck TableOneDeck = new Deck();
for (int player = 0; player &lt; 26; player++)
{
this.dataGridView1.DataSource = TableOneDeck.dt_Deck;
object[] Card1 = TableOneDeck.DealCard();
object[] Card2 = TableOneDeck.DealCard();
this.textBox1.Text += string.Format("Player: {0} Card 1: {1}{2} Card 2: {3}{4}\r\n", player, Card1[0], Card1[1], Card2[0], Card2[1]);
}



[Edited by - Gohalien on January 4, 2008 2:58:19 PM]

Share this post


Link to post
Share on other sites
I skimmed over your first post, but you made quite a few vital flaws in there. First of all, you're using an SQL server to store real-time data. It's a really bad plan to store drawn cards in a database.

It's slow as hell, esp. if you're running several games at the same time. It's better to create a list of 4 * 13 = 52 cards, shuffle it and remove cards from it as if it were a stack of cards.

You are also calling GenerateCard recursively, which will result in a StackOverflow sooner or later and crashes the application. Not what you want if you're running said application as a server. You are also using Random to pull a card, which is exploitable if someone is able to figure out the random number generator.

In your 2nd post, you show a better Deck class, which is still hitting the database. Don't. And instead of a DataSet, use a List.

To make things ever easier, why not create a Card class aswell?

Toolmaker

Share this post


Link to post
Share on other sites
Use the source tags, so the tables don't break [smile].

I don't want to start a match to write better code than you, but I wrote a simple example for cards/deck which show a different way of doing it(In this case, definitely better, because there is no database involved).

Shuffling is done by creating a GUID for each card and then sorting the List of cards based on the Guid. It's fast, uses built-in language constructs and quite simple to implement.


using System;
using System.Collections.Generic;
using System.Text;

namespace PunchTest
{
// Derive from byte so transmitting across the internet is simple
public enum CardFace : byte { Hearts, Spades, Club, Diamond }

public class Card : IComparable<Card>
{
private CardFace face;
private int value;
private Guid uid;

public Card(CardFace cardFace, int cardValue)
{
this.face = cardFace;
this.value = cardValue;
uid = new Guid(); // Used to sort the card
}

public CardFace CardFace
{
get { return face; }
}

public int Value
{
get { return value; }
}

public Guid Guid
{
get { return uid; }
}

#region IComparable<Card> Members

public int CompareTo(Card other)
{
return this.uid.CompareTo(other.Guid);
}

#endregion
}

public class Deck
{
private List<Card> cards = new List<Card>();

/// <summary>
/// Default constructor
/// </summary>
public Deck()
{
PopulateCards();
}

/// <summary>
/// Creates all cards and shuffles the deck
/// </summary>
private void PopulateCards()
{
for (int i = 2; i < 13; i++)
{
cards.Add(new Card(CardFace.Club, i));
cards.Add(new Card(CardFace.Diamond, i));
cards.Add(new Card(CardFace.Hearts, i));
cards.Add(new Card(CardFace.Spades, i));
}

cards.Sort();
}

/// <summary>
/// Draws a card from the deck
/// </summary>
/// <returns></returns>
public Card TakeCard()
{
Card c = cards[0];
cards.RemoveAt(0);

return c;
}

public int Count
{
get { return cards.Count; }
}
}
}



Toolmaker

Share this post


Link to post
Share on other sites
Ok, nice example, I made this in the night before reading your code.

class Card
{
public enum Number
{
Two = 0,
Three,
Four,
Five,
Six,
Seven,
Eight,
Nine,
Ten,
Jack,
Queen,
King,
Ace
}
public enum Suit
{
Hearts = 0,
Spades,
Diamonds,
Clubs
}
public Number number;
public Suit suit;
public Card(int n, int s)
{
number = (Number)n;
suit = (Suit)s;
}
}






Modified my code of Deck:


class Deck
{
DataTable deck = new DataTable();
public Deck()
{
deck.Columns.Add("CARDS", typeof(Card));
CreateCards();
}
private void CreateCards()
{
//Here we create the 52 cards
Card card_generated;
for (int i = 0; i < 13; i++) //Card number
{
for (int ii = 0; ii < 4; ii++) //Card suit
{
card_generated = new Card(i, ii);
deck.Rows.Add(card_generated); //We add the card to the Deck
}
}
}
public Card DealCard()
{
//Note: If we don't include the Thread.Sleep, the cards are dealed so fast that the "random" function isn't "really random"
Random random = new Random();
Card card_selected = new Card(0,0);
if (deck.Rows.Count > 0) //Here checks if our deck datatable have cards
{
int deck_row = random.Next(deck.Rows.Count);
card_selected = (Card)deck.Rows[deck_row]["CARDS"];
deck.Rows.RemoveAt(deck_row); //Delete the dealed card from the deck
}
Thread.Sleep(random.Next(1,10)); //Randomly sleep the thread to make the "random" more... ramdom -.-
return card_selected;
}
public void NewDeck()
{
deck.Clear();
CreateCards();
}
}






I am still using the deck as datatable I should use the deck as a
 Card[] Deck = new Card[52]; 




as you say in your first post, but here is my problem, when I deal a card, I don't know how to remove the selected card from the deck, I know using datatable I can use
 deck.Rows.RemoveAt(deck_row);



when I can fix that problem I will be using the deck as new Card[52] instead datatable.

Btw, what is IComparable ?
Heh don't worry, I am learning C# my code is ugly ^^
I will learn and apply your code, is way better.

Share this post


Link to post
Share on other sites
You should look at my Deck implementation. I use a List<Card>, which is a Linked List. Consider it an auto-resizing array(altho it's more complex than that, but it will suffice for now). Removing and adding to it will make the array shrink or enlarge the array data automatically. And it's faster than a DataTable.

Also, don't use my code directly out of the box. Examine it, read it, understand it. And then write your own implementation to learn some more.

And IComparable is a special type, it's an interface. It basically tells the compiler that Card will implement the behaviour IComparable describes. In this case, IComparable only has an int CompareTo(Card other) which you need to write.

When you then call cards.Sort(), the List will not see them as cards, but as IComparable's. So, in the code it will run over all the items in the list, and use item.CompareTo(otherItem) and then base the sorting on that.

Say(example time), you want to order items by their price. You have a Product class:

public class Product : IComparable<Product>
{
private float price;
...

public int CompareTo(Product other)
{
if (price < other.Price)
return -1; // This one is cheaper than other
else if (price > other.Price)
return 1; // More expensive than other
else
return 0; // Same price
}
}


If you store 2 Products in a List, with prices of 0.77 and 0.55 and then call list.Sort(), it will compare the prices of the 2(by calling CompareTo) and then see that the 0.55 one has to be placed before the 0.77 one.

Toolmaker

Share this post


Link to post
Share on other sites
Found nice poker librarys
http://www.codeproject.com/KB/cs/pokerlibraryandbotchallan.aspx
But, I will try to make them myself taking a look from that project (copy/paste doesn't teach me anything). Anyway, I think your code is better ^^ both similar, mine was ugly but again, I am learning ^^

Ok, here we go, new Deck class:

class Deck
{
Random random = new Random(DateTime.Now.Millisecond);
private List<Card> deck = new List<Card>();
public Deck()
{
CreateCards();
}
private void CreateCards()
{
//Here we create the 52 cards
for (int i = 2; i < 15; i++) //Card number
{
deck.Add(new Card(i, Card.CardSuit.Clubs));
deck.Add(new Card(i, Card.CardSuit.Diamonds));
deck.Add(new Card(i, Card.CardSuit.Hearts));
deck.Add(new Card(i, Card.CardSuit.Spades));
}
deck.Sort();
}
public Card DealCard()
{
Card c = new Card(0,Card.CardSuit.Spades);
try
{
c = deck[0];
deck.RemoveAt(0);
}
catch (ArgumentOutOfRangeException i)
{
Console.Write("No more cards! " + i);
}
return c;
}
public void NewDeck()
{
deck = new List<Card>();
CreateCards();
}
public void ShufleDeck()
{
Card card;
int temp;
//http://www.codeproject.com/KB/cs/pokerlibraryandbotchallan.aspx
for (int i = 0; i < deck.Count; i++)
{
temp = random.Next(i, deck.Count); card = deck[temp];
deck[temp] = deck[i];
deck[i] = card;
}

}
}





And of course, my main idea is to learn, so far I had no problems understanding your routines, where I had problem understanding was at ICompare/sort, but google and your explanation in your latest post helped me a lot.

BTW, I am curiouse, datatable is slow ? I thought datatable was a nice, fast way to store/sort data, thanks you for teaching me about list, it is very intuitive to use. I am still a bit confused about uid/guid, I am going now to learn more about it. Thanks for your time and willing to help us noobs.

[Edited by - Gohalien on January 4, 2008 4:03:49 PM]

Share this post


Link to post
Share on other sites
A GUID is a Global Unique Identifier, a 128-bit(16-byte) 'number', which should be unique at all times(There are a lot of combinations to generate here, so the chance of getting a double value is quite small. But given enough time, you're bound to generate the same number).

I use it as a way to sort the cards, because I'm lazy :). Your ShuffleDeck() basically does what my IComparable / List.Sort() combination does. There is no need to sort the deck if you're going to shuffle manually btw, but there is no harm in it.

I see you're handling exceptions too, good job/idea. However, in this case, it might be better to have the function that calls DealCard deal with it.

Consider this extremely simplified (psuedo) program:

Deck deck = new Deck();
// etc.
while (!gameOver)
{
Options playerSelection = GetPlayerInput();

if (playerSelection == Options.TakeCard)
{
try
{
player.GiveCard(deck.DealCard());
}
catch (ArgumentOutOfRangeException e)
{
ShowError("Oops! There are no more cards on the deck!");
}
}
}


In this case, you let the caller of DealCard handle the exception, instead of doing it inside the DealCard() function. Because if you do handle it inside the function, there is no way to find out something went wrong and you keep drawing invalid cards from the deck.

Good luck with learning. Perhaps, you should step a notch down from writing poker, to writing a more simpler game, such as GuessTheNumber:

Computer generates a random number, and player has to guess which number it is. If the guess is lower than the number, it will show "Higher" and when it's higher, it will show "Lower". If the guess equals the number, it will show "You won in x guesses", where x is the amount of attempts.

(Number = 60)
Guess? 50
Higher
Guess? 75
Lower
Guess? 63
Lower
Guess? 58
Higher
Guess? 60
You won in 5 guesses!

Toolmaker

Share this post


Link to post
Share on other sites
Thanks, I can understand now about the unique id function in C#.
I will take your advice, but I will try to make this work, I know it is hard, but I will learn a lot from it, will take me a while, but I know I can do it ^^

[Edited by - Gohalien on January 4, 2008 7:36:45 PM]

Share this post


Link to post
Share on other sites
Quote:
Original post by Toolmaker
A GUID is a Global Unique Identifier, a 128-bit(16-byte) 'number', which should be unique at all times(There are a lot of combinations to generate here, so the chance of getting a double value is quite small. But given enough time, you're bound to generate the same number).

I use it as a way to sort the cards, because I'm lazy :). Your ShuffleDeck() basically does what my IComparable / List.Sort() combination does. There is no need to sort the deck if you're going to shuffle manually btw, but there is no harm in it.

I see you're handling exceptions too, good job/idea. However, in this case, it might be better to have the function that calls DealCard deal with it.

Consider this extremely simplified (psuedo) program:

Deck deck = new Deck();
// etc.
while (!gameOver)
{
Options playerSelection = GetPlayerInput();

if (playerSelection == Options.TakeCard)
{
try
{
player.GiveCard(deck.DealCard());
}
catch (ArgumentOutOfRangeException e)
{
ShowError("Oops! There are no more cards on the deck!");
}
}
}


In this case, you let the caller of DealCard handle the exception, instead of doing it inside the DealCard() function. Because if you do handle it inside the function, there is no way to find out something went wrong and you keep drawing invalid cards from the deck.

Good luck with learning. Perhaps, you should step a notch down from writing poker, to writing a more simpler game, such as GuessTheNumber:

Computer generates a random number, and player has to guess which number it is. If the guess is lower than the number, it will show "Higher" and when it's higher, it will show "Lower". If the guess equals the number, it will show "You won in x guesses", where x is the amount of attempts.

(Number = 60)
Guess? 50
Higher
Guess? 75
Lower
Guess? 63
Lower
Guess? 58
Higher
Guess? 60
You won in 5 guesses!

Toolmaker


I took your advice, and put poker in hold, made the game you recomended me, and here it is, I will post the game here and I will love you to take a look of my code, and teach me or give me some tutorials to optimize it.

Sorry for my bad english ^^
The game (GuessTheNumber): DOWNLOAD!

Share this post


Link to post
Share on other sites
If you can find the BlackJack starter kit from Microsoft it has all the basic code you need for a deck of cards, a hand,etc that you can look at and see how it's done.
It's very similar to the code Toolmaker already posted.
And yeah even a basic game as this is alot harder and alot more code than most newbies on here assume it will take.
And if you aren't familiar with IComparable you should get a book like "Head first C#" that spends an entire chapter covering it.


This Visual C# Starter Kit is a complete BlackJack card game. The project comes ready to compile and run, and it's easy to customize with only a little extra C# programming. The section Extending the Card Game contains a list of some customizations you might make. You are also free to use the source code as the basis for your own card game projects, and share your work with others or upload it to the Internet.

Share this post


Link to post
Share on other sites
in this link there is a free open source library for poker card/decks/etc... I am studing from there, since it is very similar of Toolmaker examples, but I still need to learn some basic stuff about c# programming, that is why I started in a more easy game as he recomended me, now I am trying to improve my own code.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this