• (2 Pages)
• 1
• 2

## Playing Cards How to create a set of playing cards. (Net 3.5+) Rate Topic: 3 Votes //<![CDATA[ rating = new ipb.rating( 'topic_rate_', { url: 'http://www.dreamincode.net/forums/index.php?app=forums&module=ajax&section=topics&do=rateTopic&t=74005&amp;s=4683431c510a745bd3abbec4da21861d&md5check=' + ipb.vars['secure_hash'], cur_rating: 5, rated: 0, allow_rate: 0, multi_rate: 1, show_rate_text: true } ); //]]>

• MrCupOfT

Reputation: 2294
• Posts: 9,531
• Joined: 29-May 08

Posted 28 November 2008 - 02:50 PM

This tutorial is on how to create your pack of cards, which you can use a basis for other card games.
It'll touch on the aspects of Object Orientated Design (O.O.D.)
You'll also be using LINQ, RegEx (Regular Expressions) and creating custom sorts.

The Basics
So what is a pack of cards?
A pack of cards is collection of 52 playing cards (minus the jokers).
It can be shuffled, to rearrange to order of the cards.
Playing cards can dealt from it.

So what is a playing cards? What make each playing card unique?
A playing card is a card which is made unique by it face value and suit value.

Object Designs
We know have two objects to design (Playing Card and Deck of Cards)
Lets concentrate on the Playing Card first, as need Playing Cards to build deck.

Coding the Playing Card
```Public Class PlayingCard
Dim Suits() As String = {"S", "D", "C", "H"}
Dim Faces() As String = {"2", "3", "4", "5", "6", "7", "8", "9", "T", "J", "Q", "K", "A"}
Private mFace As String
Private mSuit As String
Protected cv As Integer = 0
Protected sv As Integer = 0

Public ReadOnly Property Suit() As String
Get
Return mSuit
End Get
End Property

Public ReadOnly Property Face() As String
Get
Return mFace
End Get
End Property

Public ReadOnly Property CardValue() As Integer
Get
Return cv
End Get
End Property

Public ReadOnly Property SuitValue() As Integer
Get
Return sv
End Get
End Property

```

You'll see have defined four (4) read-only properties (Suit, Face, FaceValue, SuitValue).

Why read-only? Cos we don't won't people changing them have been set.
So how do we set them in the first place? We set them when create (initialization) a new playing card object.
Which is what the next sub routine does.
``` Public Sub New(ByVal tSuit As String, ByVal tFaceValue As String)
mFace = tFaceValue
mSuit = tSuit
cv = Array.IndexOf(Of String)(Faces, mFace) '+ 1
sv = Array.IndexOf(Of String)(Suits, mSuit) ' + 1
End Sub

```

The next function returns a string contain the value of the card e.g. D4 for Four of Diamonds.
``` Public Overrides Function ToString() As String
Return mSuit & mFace
End Function

```

We don't want to just display text strings for each card, lets draw them a cards.
Note: Each card is a gif contained within a folder called \cards_gif, which must be in the some folder as the executable
```
Public Sub DrawCard(ByRef g As Graphics, ByRef x As Integer, ByRef y As Integer)
g.CompositingQuality = Drawing2D.CompositingQuality.GammaCorrected
g.InterpolationMode = Drawing2D.InterpolationMode.HighQualityBicubic
g.SmoothingMode = Drawing2D.SmoothingMode.HighQuality
g.DrawImage(New System.Drawing.Bitmap(System.Windows.Forms.Application.StartupPath & "\cards_gif\" & Me.ToString & ".gif"), x, y, 46, 64) '71, 96)
End Sub

```

We also want to be able to compare our playing card and since the VB.Net Framework doesn't know how to sort card, we have tell it.
``` Public Class CardComparer
Implements IComparer(Of PlayingCard)
Public Function Compare(ByVal x As PlayingCard, ByVal y As PlayingCard) As Integer Implements System.Collections.Generic.IComparer(Of PlayingCard).Compare
Dim RANKS() As String = {"A", "K", "Q", "J", "T", "9", "8", "7", "6", "5", "4", "3", "2"}
Dim xi = Array.IndexOf(Of String)(RANKS, CStr(x.ToString)(1))
Dim Yi = Array.IndexOf(Of String)(RANKS, CStr(y.ToString)(1))
Return xi.CompareTo(Yi)
End Function
End Class
End Class

```

Coding the Deck of Cards
```Public Class DeckOfCards
Dim r As New Random(Now.Millisecond)
Dim mDeck As New List(Of PlayingCard)
Dim Suits() As String = {"S", "D", "C", "H"}
Dim Faces() As String = {"2", "3", "4", "5", "6", "7", "8", "9", "T", "J", "Q", "K", "A"}

Public Sub New()
For Each Suit As String In Suits
For Each Face As String In Faces.Reverse
Next
Next
End Sub

```

We have just created a collection of playing cards. Simple isn't when you O.O.D. principles.
So we have a deck of cards but at the moment we can't do much with it, lets change that.

``` Public Sub ShuffleCards()
Dim rc As PlayingCard
Dim rn As Integer
For i As Integer = 0 To 52
rn = r.Next(0, 51) Mod mDeck.Count
rc = mDeck(rn)
mDeck.RemoveAt(rn)
Next
End Sub

```

Now it can be shuffled.
``` Public ReadOnly Property TakeCard() As PlayingCard
Get
Dim RemovedCard As PlayingCard = mDeck(0)
mDeck.RemoveAt(0)
Return RemovedCard
End Get
End Property

```

Now we can take a card from the deck.

The next property displays the state of the deck. So if you want to make cheating harder remove it.
``` Public ReadOnly Property DeckState() As String
Get
Dim d As String = ""
For Each m As PlayingCard In mDeck
d &= m.ToString
Next
Return d
End Get
End Property

End Class

```

Putting the deck of cards to use.
So now we have deck of playing cards let do something with them.
How about create a several hand of cards and sort them as if they were poker hands, with the best hand first.

Coding the hands
```Public Class HandOfCards
Protected mHand As List(Of PlayingCard)

Public Sub New()
mHand = New List(Of PlayingCard)
End Sub

Public Sub AddCard(ByVal card As PlayingCard)
If mHand.Count = 5 Then Exit Sub
End Sub

```

So now it is possible to place cards into a hand.
``` Public Function Card(ByRef index As Integer) As PlayingCard
If index < 0 Or index > 4 Then Return Nothing
Return mHand(index)
End Function

```

Refer to a card by its position in a hand.

Sort the hand by using Card Comparer we wrote earlier.
``` Public Sub SortHand()
mHand.Sort(New PlayingCard.CardComparer)
End Sub

Public Overrides Function ToString() As String
Dim s As String = ""
mHand.Sort(New PlayingCard.CardComparer)
For Each pc As PlayingCard In mHand
s &= pc.ToString
Next
Return s
End Function

Public Sub DrawHand(ByRef g As Graphics, ByRef x As Integer, ByRef y As Integer)
For i As Integer = 0 To 4
mHand(i).DrawCard(g, 10 + 25 * i, y)

Next
g.DrawString(NameOfHand, New Font("Tahoma", 16, FontStyle.Regular, GraphicsUnit.Pixel, 0), Brushes.Black, 175, y + 25)
End Sub

```

Also we can return the hand as a string or display it on a graphic surface.

The next function is a little complex, as it works out the distribution of the face values in the hand. Orders them by quantity (most to least), them by face value.
To do this we use LINQ.
``` Public Function ValueOfHand() As String
Dim DictionaryOfAlpha As New Dictionary(Of Char, Integer)
Dim Alpha() As Char = "MLKJIHGFEDCBA"
For I As Integer = 0 To Alpha.Count - 1 : DictionaryOfAlpha.Add(Alpha(I), 0) : Next
For i As Integer = 0 To mHand.Count - 1 : DictionaryOfAlpha(Alpha(mHand(i).CardValue)) += 1 : Next
Dim ReorderDictionary As IEnumerable = From DictionaryEntry In DictionaryOfAlpha _
Select DictionaryEntry _
Order By DictionaryEntry.Value Descending, _
DictionaryEntry.Key Ascending
ValueOfHand = ""
For Each Entry In ReorderDictionary : ValueOfHand &= Strings.StrDup(Entry.Value, Entry.Key) : Next
End Function

```

The next function returns a string containing the distribution of card suits in the hand.

``` Public Function SuitValueOfHand() As String
Dim n(3) As Integer
For i As Integer = 0 To mHand.Count - 1
n(mHand(i).SuitValue) += 1
Next
SuitValueOfHand = n(0).ToString & n(1).ToString & n(2).ToString & n(3).ToString
Return SuitValueOfHand
End Function

```

The next the Rank Distribution.
``` Public Function RankDistrubtion() As String
Dim n(12) As Integer
For i As Integer = 0 To mHand.Count - 1 : n(mHand(i).CardValue) += 1 : Next
RankDistrubtion = ""
For i As Integer = 12 To 0 Step -1 : RankDistrubtion &= n(i).ToString : Next
Return RankDistrubtion
End Function

```

The next function returns a string containing the poker hand of the hand of cards (eg Royal Flush or Three of a Kind etc)
``` Public Function NameOfHand() As String
Dim f As String = RankDistrubtion()
Dim s As String = SuitValueOfHand.ToString
Select Case True
Case System.Text.RegularExpressions.Regex.Match(f, "0*111110*").Success
' Contains 5 Consectative Cards
If System.Text.RegularExpressions.Regex.Match(s, "0*50*").Success Then
' Contains 5 Cards of same Suit
If f = "1111100000000" Then
Return "01. Royal Flush"
Else
Return "02. Straight Flush"
End If
Else
Return "06. Straight"
End If
Case System.Text.RegularExpressions.Regex.Match(f, "[01]*4[01]*").Success : Return "03. Four of a Kind"
Case System.Text.RegularExpressions.Regex.Match(f, "(0*20*30*)|(0*30*20*)").Success() : Return "04. Full House"
Case System.Text.RegularExpressions.Regex.Match(f, "0*10*10*10*10*10*").Success
If System.Text.RegularExpressions.Regex.Match(s, "0*50*").Success Then Return "05. Flush"
Case System.Text.RegularExpressions.Regex.Match(f, "[01]*3[01]*").Success : Return "07. Three Of a Kind"
Case System.Text.RegularExpressions.Regex.Match(f, "[01]*2[01]*2[01]*").Success() : Return "08. Two Pair"
Case System.Text.RegularExpressions.Regex.Match(f, "[01]*2[01]*").Success : Return "09. Pair"
End Select
Return "10. High Card"
End Function

```

This is achieved by looking for patterns in the distribution of both the card values of suits. The best object to use for pattern matching is a RegEx or Regular Expression.
So a royal flush is SASKSQSJST or 1111100000000 for the value distribution and "0*50*" for the suit distribution.

Since VB.Net doesn't know how to compare to hands of cards, we have to tell it how.
``` Public Class HandComparer
Implements IComparer(Of HandOfCards)
Public Function Compare(ByVal x As HandOfCards, ByVal y As HandOfCards) As Integer Implements System.Collections.Generic.IComparer(Of HandOfCards).Compare
Dim c As Integer = x.NameOfHand.Substring(0, 2).CompareTo(y.NameOfHand.Substring(0, 2))
Select Case c
Case -1, 1 : Return c
Case 0 : Return String.Compare(x.ValueOfHand, y.ValueOfHand)
End Select
End Function
End Class
End Class

```

The Demonstration Form

Create a windows form. Add button then insert this code.
```Public Class Form1
Dim TheDeck As DeckOfCards
Dim Hands(NumberOfHands - 1) As HandOfCards
Const NumberOfHands As Integer = 10

Private Sub Form1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
If TheDeck IsNot Nothing Then
For i = 0 To NumberOfHands - 1
Hands(i).DrawHand(e.Graphics, 25, 25 + i * 65)
Next
End If

End Sub

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Console.WriteLine("--------")

TheDeck = New DeckOfCards
TheDeck.ShuffleCards()
TheDeck.ShuffleCards()
'TheDeck.ShuffleCards()
' TheDeck.ShuffleCards()
For i = 0 To NumberOfHands - 1
Hands(i) = New HandOfCards
For c As Integer = 0 To 4
Next
Hands(i).SortHand()
Next
Array.Sort(Hands, New HandOfCards.HandComparer)
For i = 0 To NumberOfHands - 1
Console.WriteLine("{0}" & vbTab & "[{1}] = {2}" & vbTab & " {3}" & vbTab & "[{4}]" & vbTab & " ({5})", i + 1, Hands(i).ToString, Hands(i).SuitValueOfHand, Hands(i).RankDistrubtion, Hands(i).NameOfHand, Hands(i).ValueOfHand)
Next
'Console.WriteLine("Deck [{0}]", TheDeck.DeckState)
'Console.WriteLine("Deck [{0}]", TheDeck.DeckState)
'TheDeck.ShuffleCards()
'Console.WriteLine("Deck [{0}]", TheDeck.DeckState)
Me.Refresh()
End Sub
End Class

```

Run.

So now you're Poker Hand Sorting Code Ninja

Project Files:  PlayingCards.zip (173.67K)

Is This A Good Question/Topic? 4

## Replies To: Playing Cards

### #2 jimdandy75

• D.I.C Regular

Reputation: 37
• Posts: 311
• Joined: 30-June 08

Posted 03 May 2009 - 07:27 AM

WOW!!!!! That is awesome..... Thanks
I see alot of card game questions on the boards they should be directed here.
I tried tweeking this a little to see if I could get it to deal out a 7 card hand and
return the best 5 card poker hand, like in Texas Hold Em. But my coding skills are
weak Could you possibly extend this tutorial to show that?

This post has been edited by jimdandy75: 03 May 2009 - 11:25 AM

• MrCupOfT

Reputation: 2294
• Posts: 9,531
• Joined: 29-May 08

Posted 03 May 2009 - 04:32 PM

Texas-Holdem like play.

Add this to the DeckOfCards Class
``` Public ReadOnly Property CardsLeft() As Integer
Get
Return mDeck.Count

End Get
End Property

```

modified DrawHand also.
```
Public Sub DrawHand(ByRef g As Graphics, ByRef x As Integer, ByRef y As Integer,optional ByRef t As Boolean=True)
For i As Integer = 0 To mHand.Count - 1
mHand(i).DrawCard(g, 10 + 25 * i, y)

Next
If t Then g.DrawString(NameOfHand, New Font("Tahoma", 16, FontStyle.Regular, GraphicsUnit.Pixel, 0), Brushes.Black, 175, y + 25)
End Sub

```

Create a new project or form, if you're creating a new form in the tutorial project remember to set the startup form to the new one

Add a couple of buttons;- Hand (Players Cards) & Dealt (River cards)

```Public Class TexasHoldem
Dim TheDeck As DeckOfCards
Dim Hands(NumberOfHands - 1) As HandOfCards
Dim Dealt As HandOfCards
Dim BestHandIs As HandOfCards

Const NumberOfHands As Integer = 1
Dim a As New List(Of String)
Dim b As New List(Of String)

Private Sub TexasHoldem_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
MchooseN(3, 0, 4, a)
MchooseN(4, 0, 4, b)

End Sub

Private Sub Form1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
If TheDeck IsNot Nothing Then
For i = 0 To NumberOfHands - 1
Hands(i).DrawHand(e.Graphics, 25, 100 + i * 65, False)
If Dealt IsNot Nothing Then Dealt.DrawHand(e.Graphics, 25, 175 + i * 65, False)
If lh IsNot Nothing AndAlso lh.Count > 0 Then
BestHandIs.DrawHand(e.Graphics, 25, 250 + i * 65, True)
End If
Next
End If

End Sub

Private Function BestHand(ByRef meCards As HandOfCards, ByRef rc As HandOfCards) As HandOfCards
If meCards Is Nothing Then Return Nothing
If rc Is Nothing Then Return Nothing

lh.Clear()

Dim an As HandOfCards
For Each aa As String In a
an = New HandOfCards

For i As Integer = 0 To 2
Next
an.SortHand()

Next
For j As Integer = 0 To 1
For Each aa As String In b
an = New HandOfCards

For i As Integer = 0 To 3
Next
an.SortHand()
Next
Next
lh.Sort(hc)

Return lh(0)

End Function

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
If TheDeck Is Nothing Then newdeck()

If TheDeck.CardsLeft < 5 Then newdeck()

TheDeck = New DeckOfCards
TheDeck.ShuffleCards()
TheDeck.ShuffleCards()
For i As Integer = 0 To NumberOfHands - 1
Hands(i) = New HandOfCards

For c As Integer = 0 To 1
Next
Hands(i).SortHand()

Next
BestHandIs = BestHand(Hands(0), Dealt)

Me.Refresh()

End Sub
Private Sub newdeck()

TheDeck = New DeckOfCards
TheDeck.ShuffleCards()
TheDeck.ShuffleCards()

End Sub

Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
If TheDeck.CardsLeft < 5 Then newdeck()
Dealt = New HandOfCards

For i As Integer = 0 To 4
Next
Dealt.SortHand()
BestHandIs = BestHand(Hands(0), Dealt)

Me.Refresh()

End Sub
Dim hc As New HandOfCards.HandComparer
Dim lh As New List(Of HandOfCards)

Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
BestHandIs = BestHand(Hands(0), Dealt)
Me.Refresh()

End Sub

Private Sub MchooseN(ByRef N As Integer, ByRef first_allowed As Integer, ByRef last_allowed As Integer, ByRef solutions As List(Of String))
Dim i As Integer = 0
Dim txt As New System.Text.StringBuilder
Dim partial_solutions As List(Of String)
Dim fapo As Integer = first_allowed + 1
Dim lmf As Integer = last_allowed - first_allowed + 1
' Change spacer to alter character between numbers.
Const Spacer As String = ""
' If N < 1, we don't need to pick any more items.
' If N > last_allowed - first_allowed + 1, there are too few items for a solution.
' If N = last_allowed - first_allowed + 1,' all the items must be in the solution.
Select Case True
Case N < 1 ' We don't need to pick any more, Do nothing.
Case N > lmf ' There are not enough items. Do nothing.
Case N = lmf
' All the items must be in the solution.
txt.Append(Format\$(first_allowed))
For i = fapo To last_allowed
txt.Append(Format\$(i) & Spacer)
Next i
Case Else
'Get solutions containing first_allowed.
partial_solutions = New List(Of String)
If N = 1 Then
Else
MchooseN(N - 1, fapo, last_allowed, partial_solutions)
End If
' Add first_allowed to make the full solutions.
For i = 0 To partial_solutions.Count - 1
Next i
' Get solutions not containing first_allowed.
partial_solutions = New List(Of String)
MchooseN(N, fapo, last_allowed, partial_solutions)
' Add these to the solutions.
End Select
End Sub
End ClassEnd Class

```

Some of you may have noticed that this is only a players hand.
It is left as an exercise for the reader to extend to multiple players.

This post has been edited by AdamSpeight2008: 03 May 2009 - 05:31 PM

### #4 jimdandy75

• D.I.C Regular

Reputation: 37
• Posts: 311
• Joined: 30-June 08

Posted 03 May 2009 - 05:56 PM

Yup, you da man!!!!! Thank you, it works great

### #5 DataPriest

Reputation: 20
• Posts: 57
• Joined: 29-April 09

Posted 20 August 2009 - 11:21 PM

Good work man. Loved the code.

### #6 Randomluck

Reputation: 0
• Posts: 5
• Joined: 02-December 09

Posted 02 December 2009 - 03:42 PM

First, thanks for the example, it is very nice. Second, I do have a question on how to proceed with the following example:

Taking this example:
We have the class of "PlayingCard". What if we extend the class to two new classes "Class CardA inherits PlayingCard" and "Class CardB inherits PlayingCards". Each class has an additional distinct set of properties.

Now, I'd like to reuse the DeckOfCards object (for the shuffle and drawcards function), but I'd like CardA and a second DeckOfCards using CardB.

When I've tried this code at home VS has thrown an "The type initializer for 'BSGEngine.modGlobals' threw an exception." error and crashes. Is what I'm talking about feasible or would I need a "DeckOfCards" object specified for each class of playing Cards I create?

Thanks and I appreciate your input.

• MrCupOfT

Reputation: 2294
• Posts: 9,531
• Joined: 29-May 08

Posted 04 May 2010 - 12:19 AM

See this post for solution to Randomluck's problem.

### #8 Peanut373

Reputation: 0
• Posts: 6
• Joined: 07-December 09

Posted 12 May 2010 - 12:55 PM

I appreciate the tutorial but I am getting a couple of errors when I run the program. Why is this?

### #9 tguns17

Reputation: 0
• Posts: 1
• Joined: 26-June 09

Posted 16 June 2010 - 11:05 AM

I have been searching for code on card games and I feel like I've been everywhere. I really liked the code you provide at http://www.dreaminco...-playing-cards/
but for some reason I must not be entering it into vb.net correctly. I have also tried to download the PlayingCards.zip file and that didn't work either. I am very new to vb and am trying to program video poker card games. Can you send me the files that you used so that I can see exactly how to put these into a visual basic. Thanks.

### #10 ankitj86

Reputation: 0
• Posts: 2
• Joined: 12-October 10

Posted 12 October 2010 - 02:43 PM

Awesome Work!!!! I have been looking for a poker game logic for a long time and your code works BEAUTIFULLY. I am looking to do some modifications in the game, but I am fairly new to VB coding.

I have placed two containers (picture-boxes) on the form and I want the user two enter the two cards. Now, I want the program to deal out 5 random cards from the deck, after excluding the two cards already entered. Finally I am looking it to calculate all 7 cards for the hand.
But I am not sure what all modifications to the code it would need.

Thanks

### #11 colossus1958

Reputation: 0
• Posts: 11
• Joined: 02-March 10

Posted 01 February 2011 - 01:33 PM

[quote name='AdamSpeight2008' date='28 November 2008 - 02:50 PM' timestamp='1227909048' post='475888']
This tutorial is on how to create your pack of cards, which you can use a basis for other card games.
It'll touch on the aspects of Object Orientated Design (O.O.D.)
You'll also be using LINQ, RegEx (Regular Expressions) and creating custom sorts...

I really like this code. Short and to the point. If you are looking for help on coding poker games. Solitaire games are another story however. I have been searching on-line for over a year now, and while I've found bits and pieces that have helped me out (drag-and-drop, shuffle, etc.) I have yet to see a tutorial based around the creation of a solitaire game. I haven't given up yet. Maybe you know some places to go that I don't. (I have been through Google with every variation I could think of.)

### #12 Blind_Geek81

Reputation: 0
• Posts: 11
• Joined: 28-February 11

Posted 02 May 2011 - 05:54 PM

This will help me SO much with my Blackjack game! It is version 4 of one of my finals! I've been switching between C# and VB since the day I got the assignment, and I've gotta say, my VB project is going much smoother than my C# ones have! Now if only I could translate my console game to a windows form...yikes!!

### #13 PickyBiker

Reputation: 1
• Posts: 2
• Joined: 12-January 12

Posted 12 January 2012 - 02:05 PM

This is terrific. I did notice that if the NumberOfDecks constant is made greater than 10, something breaks. I am trying to find out why.

PickyBiker

PickyBiker, on 12 January 2012 - 02:04 PM, said:

This is terrific. I did notice that if the NumberOfDecks constant is made greater than 10, something breaks. I am trying to find out why.

PickyBiker

I meant NumberOfHands constant

### #14 PickyBiker

Reputation: 1
• Posts: 2
• Joined: 12-January 12

Posted 12 January 2012 - 02:34 PM

PickyBiker, on 12 January 2012 - 02:05 PM, said:

This is terrific. I did notice that if the NumberOfDecks constant is made greater than 10, something breaks. I am trying to find out why.

PickyBiker

PickyBiker, on 12 January 2012 - 02:04 PM, said:

This is terrific. I did notice that if the NumberOfDecks constant is made greater than 10, something breaks. I am trying to find out why.

PickyBiker

I meant NumberOfHands constant

Figured it out. After 10 hands have been dealt, there are not enough cards left in the deck for another hand so after the 2nd card in the 11th hand is dealt, the attempt to take another card fails.... Duh!

### #15 ana.O

Reputation: 0
• Posts: 1
• Joined: 13-July 12

Posted 13 July 2012 - 10:46 AM

Great tutorial!!!

How implemente and use jokers??!!