Share via


VB.Net: Three-card Monte

Overview

[Quote wiki: https://en.wikipedia.org/wiki/Three-card_Monte]

"Three-card Monte - also known as find the lady and three-card trick - is a confidence game in which the victim, or "mark", is tricked into betting a sum of money, on the assumption that they can find the "money card" among three face-down playing cards. It is the same as the shell game except that cards are used instead of shells.

In its full form, three-card Monte is an example of a classic "short con" in which a shill pretends to conspire with the mark to cheat the dealer, while in fact conspiring with the dealer to cheat the mark. The mark has no chance whatsoever of winning, at any point in the game. In fact, anyone who is observed winning anything in the game can be presumed to be a shill.

This confidence trick was already in use by the turn of the 15th century."

This is a card game based on Three-card Monte, with the exception being, this is the honest version.

The levelControl

This control is hosted in a menuitem and used for setting the speed of card shuffling.

Public Class  levelControl
 
 Public Event  ValueChanged(sender As Object, e As  EventArgs)
 
 Public Property  Value() As  Integer
 Get
 Return HScrollBar1.Value
 End Get
 Set(ByVal value As Integer)
 HScrollBar1.Value = value
 End Set
 End Property
 
 Public Property  Minimum() As  Integer
 Get
 Return HScrollBar1.Minimum
 End Get
 Set(ByVal value As Integer)
 HScrollBar1.Minimum = value
 End Set
 End Property
 Public Property  Maximum() As  Integer
 Get
 Return HScrollBar1.Maximum
 End Get
 Set(ByVal value As Integer)
 HScrollBar1.Maximum = value
 End Set
 End Property
 
 Private Sub  HScrollBar1_ValueChanged(sender As Object, e As  EventArgs) Handles HScrollBar1.ValueChanged
 RaiseEvent ValueChanged(Me, New  EventArgs)
 End Sub
 
End Class

The Form code

Most of the code is encapsulated in Form1. This is because, as a highly graphical game, it wouldn't be appropriate to move the code to Classes. The cost would outweigh the benefits in terms of code concision...

Public Class  Form1
 
 Dim images As New  Dictionary(Of Object, Bitmap)
 
 'these 6 arrays are used in the animation effects
 Dim Points1() As Point = New Point() {
 New Point(388, 186),
 New Point(388, 161),
 New Point(368, 136),
 New Point(338, 116),
 New Point(298, 116),
 New Point(268, 136),
 New Point(248, 161),
 New Point(248, 186)}
 
 Dim Points2() As Point = New Point() {
 New Point(248, 186),
 New Point(248, 211),
 New Point(268, 236),
 New Point(298, 256),
 New Point(338, 256),
 New Point(368, 236),
 New Point(388, 211),
 New Point(388, 186)}
 
 Dim Points3() As Point = New Point() {
 New Point(248, 186),
 New Point(248, 161),
 New Point(228, 136),
 New Point(198, 116),
 New Point(158, 116),
 New Point(128, 136),
 New Point(108, 161),
 New Point(108, 186)}
 
 
 Dim Points4() As Point = New Point() {
 New Point(108, 186),
 New Point(108, 211),
 New Point(128, 236),
 New Point(158, 256),
 New Point(198, 256),
 New Point(228, 236),
 New Point(248, 211),
 New Point(248, 186)}
 
 
 Dim Points5() As Point = New Point() {
 New Point(388, 186),
 New Point(388, 161),
 New Point(368, 136),
 New Point(338, 116),
 New Point(298, 96),
 New Point(248, 96),
 New Point(198, 96),
 New Point(158, 116),
 New Point(128, 136),
 New Point(108, 161),
 New Point(108, 186)}
 
 
 Dim Points6() As Point = New Point() {
 New Point(108, 186),
 New Point(108, 211),
 New Point(128, 236),
 New Point(158, 256),
 New Point(198, 276),
 New Point(248, 276),
 New Point(298, 276),
 New Point(338, 256),
 New Point(368, 236),
 New Point(388, 211),
 New Point(388, 186)}
 
 Dim upper() As Point = Nothing
 Dim lower() As Point = Nothing
 Dim loopIndex As Integer
 Dim increment As Integer
 Dim fixed As Integer
 Dim showCards As Boolean  = False
 Dim r As New  Random
 Dim sw As New  Stopwatch
 Dim after() As String
 Dim rgns(2) As Region
 Dim showFace() As Boolean
 Dim canChoose As Boolean  = False
 
 Private WithEvents  tmr As  New Timer With {.Interval = 40}
 Private WithEvents  hsb As  New levelControl With {.Minimum = 25, .Maximum = 100, .Value = 40}
 
 'clickable regions are used in allowing the card images to respond to clicking
 Private Sub  Form1_Load(sender As Object, e As  EventArgs) Handles MyBase.Load
 images.Add("Queen", My.Resources.queen)
 images.Add("King", My.Resources.king)
 images.Add("Ace", My.Resources.ace)
 images.Add("Back", My.Resources.back)
 
 Dim r As New  Rectangle(New  Point(Points4(0).X - 36, Points4(0).Y - 48), New Size(72, 96))
 rgns(0) = New  Region(r)
 r = New  Rectangle(New  Point(Points2(0).X - 36, Points2(0).Y - 48), New Size(72, 96))
 rgns(1) = New  Region(r)
 r = New  Rectangle(New  Point(Points1(0).X - 36, Points1(0).Y - 48), New Size(72, 96))
 rgns(2) = New  Region(r)
 
 DifficultyToolStripMenuItem.DropDownItems.Add(New ToolStripControlHost(hsb))
 
 Me.DoubleBuffered = True
 Me.SetClientSizeCore(504, 396)
 End Sub
 
 'captures card clicking
 Private Sub  Form1_MouseDown(sender As Object, e As  MouseEventArgs) Handles Me.MouseDown
 If e.Button = MouseButtons.Left Then
 If canChoose Then
 Dim x As Integer  = Array.FindIndex(rgns, Function(rgn) rgn.IsVisible(e.Location))
 If x > -1 Then
 showFace(x) = True
 canChoose = False
 Button1.Enabled = True
 Me.Refresh()
 End If
 End If
 End If
 End Sub
 
 'the animations are purely GDI+
 Private Sub  Form1_Paint(ByVal sender As Object, ByVal  e As  System.Windows.Forms.PaintEventArgs) Handles Me.Paint
 If showcards Then
 e.Graphics.DrawImage(If(showFace(0), images(after(0)), images("Back")), New  Point(Points4(0).X - 36, Points4(0).Y - 48))
 e.Graphics.DrawImage(If(showFace(1), images(after(1)), images("Back")), New  Point(Points2(0).X - 36, Points2(0).Y - 48))
 e.Graphics.DrawImage(If(showFace(2), images(after(2)), images("Back")), New  Point(Points1(0).X - 36, Points1(0).Y - 48))
 Return
 End If
 If upper Is Nothing  Then Return
 Select Case  fixed
 Case 0
 e.Graphics.DrawImage(images("Back"), New  Point(Points4(0).X - 36, Points4(0).Y - 48))
 Case 1
 e.Graphics.DrawImage(images("Back"), New  Point(Points2(0).X - 36, Points2(0).Y - 48))
 Case 2
 e.Graphics.DrawImage(images("Back"), New  Point(Points1(0).X - 36, Points1(0).Y - 48))
 End Select
 e.Graphics.DrawImage(images("Back"), New  Point(upper(loopIndex).X - 36, upper(loopIndex).Y - 48))
 e.Graphics.DrawImage(images("Back"), New  Point(lower(loopIndex).X - 36, lower(loopIndex).Y - 48))
 End Sub
 
 Private Sub  Button1_Click(ByVal sender As System.Object, ByVal  e As  System.EventArgs) Handles Button1.Click
 Button1.Enabled = False
 after = New  String() {"Queen", "King", "Ace"}.OrderBy(Function(s) r.NextDouble).ToArray
 showFace = New  Boolean() {True, True, True}
 showcards = True
 Me.Refresh()
 Threading.Thread.Sleep(1250)
 showFace = New  Boolean() {False, True, True}
 Me.Refresh()
 Threading.Thread.Sleep(250)
 showFace = New  Boolean() {False, False, True}
 Me.Refresh()
 Threading.Thread.Sleep(250)
 showFace = New  Boolean() {False, False, False}
 Me.Refresh()
 Threading.Thread.Sleep(250)
 nextMove()
 sw = Stopwatch.StartNew()
 tmr.Enabled = True
 End Sub
 
 Private Sub  tmr_Tick(ByVal sender As Object, ByVal  e As  System.EventArgs) Handles tmr.Tick
 showcards = False
 If increment = -1 Then
 If loopIndex + increment < 0 Then
 If sw.Elapsed < New TimeSpan(0, 0, 10) Then
 nextMove()
 Else
 tmr.Stop()
 showcards = True
 canChoose = True
 End If
 Else
 loopIndex += increment
 End If
 Else
 If loopIndex + increment > upper.GetUpperBound(0) Then
 If sw.Elapsed < New TimeSpan(0, 0, 10) Then
 nextMove()
 Else
 tmr.Stop()
 showcards = True
 canChoose = True
 End If
 Else
 loopIndex += increment
 End If
 End If
 Me.Refresh()
 End Sub
 
 'this method changes the variables used in the animation, allowing different moves
 Private Sub  nextMove()
 Dim move As Integer  = r.Next(0, 6)
 
 Select Case  move
 Case 0
 upper = Points1
 lower = Points2
 increment = 1
 fixed = 0
 loopIndex = 0
 Dim temp As String  = after(1)
 after(1) = after(2)
 after(2) = temp
 Case 1
 upper = Points3
 lower = Points4
 increment = 1
 fixed = 2
 loopIndex = 0
 Dim temp As String  = after(0)
 after(0) = after(1)
 after(1) = temp
 Case 2
 upper = Points5
 lower = Points6
 increment = 1
 fixed = 1
 loopIndex = 0
 Dim temp As String  = after(0)
 after(0) = after(2)
 after(2) = temp
 Case 3
 upper = Points1
 lower = Points2
 increment = -1
 fixed = 0
 loopIndex = upper.GetUpperBound(0)
 Dim temp As String  = after(2)
 after(2) = after(1)
 after(1) = temp
 Case 4
 upper = Points3
 lower = Points4
 increment = -1
 fixed = 2
 loopIndex = upper.GetUpperBound(0)
 Dim temp As String  = after(0)
 after(0) = after(1)
 after(1) = temp
 Case 5
 upper = Points5
 lower = Points6
 increment = -1
 fixed = 1
 loopIndex = upper.GetUpperBound(0)
 Dim temp As String  = after(0)
 after(0) = after(2)
 after(2) = temp
 End Select
 
 End Sub
 Private Sub  hsb_ValueChanged(sender As Object, e As  EventArgs) Handles hsb.ValueChanged
 tmr.Interval = hsb.Value
 End Sub
 
End Class

Conclusion

This example shows how to create a lightweight GDI+ card game, with simple animations.

 

Download

Download here