Results 1 to 13 of 13

Thread: [RESOLVED] Good ol' Blackjack Project

  1. #1

    Thread Starter
    New Member Jaycoba's Avatar
    Join Date
    Nov 2017
    Location
    In the sands of time.
    Posts
    13

    Resolved [RESOLVED] Good ol' Blackjack Project

    Blackjack seems to be a very highly used project among computer languages, if not card games in general. There are so many different variations of how one can do this, so I'm back asking more questions for some clarity and peace of mind.

    The project is pretty self explanatory, but it doesn't have all the options as a "Hoyle Casino 4" Blackjack game, leaving out splitting, doubling down, and surrendering. I have 5 players; myself, the dealer, and 3 other players that I have to code for. I think I have most aspects under control, though I'm having trouble assigning values to the card images.

    I didn't want to jump ahead, knowing that the values of the cards is a crucial aspect. Going any further might jeopardize the work I put into the project and I don't like doing things more times than I need to.

    This is what I have so far:

    Code:
        Public Class Form1
        'Jacob T. Miller
        '11/15/2017
    
        'Variables
        Dim timer As New System.Diagnostics.Stopwatch
        Dim time As Single
    
        Dim picbox As System.Drawing.Graphics = Me.CreateGraphics
    
        'Playing Cards
        Dim backOfCards As Object = My.Resources.Back_of_cards
        Dim playingcard(,) As Image =
        {{My.Resources.Ace_of_Clubs, My.Resources.Two_of_Clubs, My.Resources.Three_of_Clubs, My.Resources.Four_of_Clubs,
        My.Resources.Five_of_Clubs, My.Resources.Six_of_Clubs, My.Resources.Seven_of_Clubs, My.Resources.Eight_of_Clubs,
        My.Resources.Nine_of_Clubs, My.Resources.Ten_of_Clubs, My.Resources.Jack_of_Clubs, My.Resources.Queen_of_Clubs,
        My.Resources.King_of_Clubs},
        {My.Resources.Ace_of_Diamonds, My.Resources.Two_of_Diamonds, My.Resources.Three_of_Diamonds, My.Resources.Four_of_Diamonds,
        My.Resources.Five_of_Diamonds, My.Resources.Six_of_Diamonds, My.Resources.Seven_of_Diamonds, My.Resources.Eight_of_Diamonds,
        My.Resources.Nine_of_Diamonds, My.Resources.Ten_of_Diamonds, My.Resources.Jack_of_Diamonds, My.Resources.Queen_of_Diamonds,
        My.Resources.King_of_Diamonds},
        {My.Resources.Ace_of_Hearts, My.Resources.Two_of_Hearts, My.Resources.Three_of_Hearts, My.Resources.Four_of_Hearts,
        My.Resources.Five_of_Hearts, My.Resources.Six_of_Hearts, My.Resources.Seven_of_Hearts, My.Resources.Eight_of_Hearts,
        My.Resources.Nine_of_Hearts, My.Resources.Ten_of_Hearts, My.Resources.Jack_of_Hearts, My.Resources.Queen_of_Hearts,
        My.Resources.King_of_Hearts},
        {My.Resources.Ace_of_Spades, My.Resources.Two_of_Spades, My.Resources.Three_of_Spades, My.Resources.Four_of_Spades,
        My.Resources.Five_of_Spades, My.Resources.Six_of_Spades, My.Resources.Seven_of_Spades, My.Resources.Eight_of_Spades,
        My.Resources.Nine_of_Spades, My.Resources.Ten_of_Spades, My.Resources.Jack_of_Spades, My.Resources.Queen_of_Spades,
        My.Resources.King_of_Spades}}
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Randomize()
            timer.Start()
            time = timer.Elapsed.Seconds
            If time < 1 Then PictureBox1.Image = playingcard(Rnd() * 3, Rnd() * 12)
        End Sub
    End Class
    It was at the very bottom of the code that I realized... I don't have set values and I don't know how to do it without it throwing some error at me. That and the card is covered by the other picture boxes over top of it, but I think I can just make those transparent until they have an image set within them. I'm not for certain though, so some tomfoolery might answer that question.

    The stop watch was meant to give the dealer time to pass around the cards in sequence. Like I said, I think I have an idea of how to set the game up (even though it may not be optimal), I just don't know how to assign values to images, if that's even possible.

    I'm going to keep reading and messing with the options to see if I can't figure it out.

  2. #2
    You don't want to know.
    Join Date
    Aug 2010
    Posts
    4,578

    Re: Good ol' Blackjack Project

    There are a lot of ways to go about it. Here's one.

    A card like "nine of clubs" has two interesting things to know about: its value and its suit. Every card has those two things. When we end up saying something like that describing one of our program's data types, it usually means we should represent it as a class. So we could:
    Code:
    Public Class Card
    
        Public Const Jack As Integer = 10
        Public Const Queen As Integer = 11
        Public Const King As Integer = 12
        Public Const Ace As Integer = 13 ' You might also choose 1. Toughie.
    
        Public Property Value As Integer
        Public Property Suit As Suit
    End Class
    
    Public Enum Suit
        Hearts,
        Diamonds,
        Clubs,
        Spades
    End Class
    If you want to support a Joker, you'll have to figure that out. We're going to ignore the Joker for simplicity.

    Using this, we can make a deck of cards in a hurry:
    Code:
    Dim deck As New List(Of Card)()
    
    For Each cardSuit In { Suit.Hearts, Suit.Diamonds, Suit.Clubs, Suit.Spades }
        For cardValue As Integer = 2 To 13
            deck.Add(New Card() With { .Value = cardValue, .Suit = cardSuit })
        Next
    Next
    Shuffle.

    How do we associate it with an image? Well, we can do some fancy things if we're drawing our own cards, but let's just go with what you have: a buttload of images.

    The easiest thing would be "a dictionary associating a card with an image". For reasons I won't get into, that won't work without some extra effort. Let's be a little more clever so we can be a little more lazy.

    Every suit has images for the cards with values 2 through 13. (Or 1 through 12, depending on how you set up Ace.) So we could say every suit an array of 13 images determined by the value on the card. We can make all the "hearts" like:
    Code:
    Dim hearts() As Image = { My.Resources.Two_Of_Hearts, My.Resources.Three_Of_Hearts, ..., My.Resources.Ace_Of_Hearts }
    We can make a dictionary that goes from card suit to that array, then make a helper for us to work with it.
    Code:
    Dim cardImages As New Dictionary(Of Suit, Image())() = {
        { Suit.Hearts, hearts },
        { Suit.Diamonds, diamonds },
        { Suit.Clubs, clubs }
        { Suit.Spades, spades }
    }
    Code:
    Public Function GetImageFrom(ByVal card As Card) As Image
        ' "2 of ?" is at index 0, "ace of ?" is at 11.
        Dim index = card.Value - 2
        Return cardImages(card.Suit)(index)
    End Function
    Kablam.

    More elegant approaches involve tricks like:
    • Naming the cards in a pattern you can generate from value/suit and using string indexing in My.Resources so you don't have to type out 50 card images.
    • Drawing bits of the card yourself, all you really need is number, suit, and face images.
    • Implementing IEquatable so Card works more directly in Dictionaries.
    • Mapping the numbers 0-49 such that they all represent one of the cards, then using conversion functions to go back and forth.
    This answer is wrong. You should be using TableAdapter and Dictionaries instead.

  3. #3
    PowerPoster Jenner's Avatar
    Join Date
    Jan 2008
    Location
    Mentor, OH
    Posts
    3,712

    Re: Good ol' Blackjack Project

    Sitten Spynne layed out perhaps the easiest way to do it from scratch. I highly recommend following his advice. Object oriented programming can REALLY be taken advantage of in card games. You have Cards - a fixed number of objects that have a value. You have Decks - which are collections of Cards... either to "Draw" from or "Discard" to. You have Players - which are objects that have a "Deck" associated to them (their hand). The rest is just wiring things together.
    My CodeBank Submissions: TETRIS using VB.NET2010 and XNA4.0, Strong Encryption Class, Hardware ID Information Class, Generic .NET Data Provider Class, Lambda Function Example, Lat/Long to UTM Conversion Class, Audio Class using BASS.DLL

    Remember to RATE the people who helped you and mark your forum RESOLVED when you're done!

    "Two things are infinite: the universe and human stupidity; and I'm not sure about the universe. "
    - Albert Einstein

  4. #4

    Thread Starter
    New Member Jaycoba's Avatar
    Join Date
    Nov 2017
    Location
    In the sands of time.
    Posts
    13

    Re: Good ol' Blackjack Project

    Sorry it took me a few days to reply, have been rather busy. We haven't gone over dictionaries in class yet, so I'll have to read over it a few times to grasp the concept. I may not be able to use things in my class that we haven't covered, but as long as the outcome is what my teacher wants, I think it will be okay. I've used a few things suggested from these forums already and he doesn't seem to mind.

    Quote Originally Posted by Jenner View Post
    The rest is just wiring things together.
    Those were my thoughts exactly when posting this thread. I just needed to find out how to get everything to associate with the next.

    Thank you both for your replies!

  5. #5
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    39,039

    Re: Good ol' Blackjack Project

    I'm not sure that you actually want that Stopwatch, but I also didn't realize this was a class project. What you really want is a Timer, and a different way of looking at things. The Stopwatch is pretty cool for measuring elapsed time very accurately, but that's not really what you are doing. What you want is to have things happen periodically (a card is dealt every so often). You can do that with a busy wait, but then we'll jump on you about it. A Timer is the thing you need.

    With a timer, you set an interval. You really don't want that interval to be less than 100 (it's in milliseconds, so that's a tenth of a second, which is too fast for dealing anyways). You might start off with an interval of 200, and play around with it from there. The Timer has only one event, the Tick event, which is raised roughly once every interval as long as the Timer is running. So, when you start the Timer with an interval of 200, you get the Tick event handler method being called once every 200ms....roughly. The accuracy isn't great, as plenty of other things can get in the way, but it will be close enough that you won't see the difference most of the time.

    So, the different way of looking at things is to start the timer, and in the tick event, deal each card. People often try to do things like that in a loop, and this IS a loop, it's just that it's a loop without a Do, For, or anything like that. It's just a loop where every iteration happens once every interval of the timer.

    Also, Dictionaries are pretty awesome. You can tie any unique key item to any value item. I'm not quite sure why Sitten felt that "a dictionary associating a card with an image" wouldn't work, because both the image and the card would be unique, so either one could be the key, as far as I can see. I'm not sure that you'd want to do that, but it seems like you could have a card as the key and the image as the value, or vice versa.

    However, it seems to me that the image is a member of the card, and the constructor of the card could take an image as one argument.
    My usual boring signature: Nothing

  6. #6
    You don't want to know.
    Join Date
    Aug 2010
    Posts
    4,578

    Re: Good ol' Blackjack Project

    You can "dumb down" my solution a little bit and drop the Dictionary:

    If you have an "array of Card", you could also say you have a "Dictionary(Of Integer, Card)". When we talk about Dictionary(Of X, Y), it's really a lot like an array where instead of using numbers, you use things of type X to get things of type Y. If you squint real hard, an "array of Card" is a thing where you use things of type Integer to get things of type Card.

    (There is a difference, and it makes a good job interview question, but it's not important to the topic.)

    So if you instead represent Suits by integer constants:
    Code:
    Constant Suit_Hearts As Integer = 0
    Constant Suit_Diamonds As Integer = 1
    ...
    You could make a 2D array instead of a dictionary with a little bit of a tweak:
    Code:
    Dim cardImages()() As Image = {
        { hearts },
        { diamonds },
        { clubs }
        { spades }
    }
    This is "an array of arrays of images" and programmers really love stupid concepts like that. I might have some parenthesis in the wrong place, but if you mess around with them you'll figure out how to satisfy the ancient VB syntax requirements.

    Array is a very primitive data type. You can build all kinds of other neat data structures out of it if you play around with it, so it's almost always true if someone uses a fancy type you can't use, you can find a way to implement that type in terms of an array. ("Primitive" doesn't mean "bad". It really means "the kind of LEGO brick you use all the time".)
    This answer is wrong. You should be using TableAdapter and Dictionaries instead.

  7. #7

    Thread Starter
    New Member Jaycoba's Avatar
    Join Date
    Nov 2017
    Location
    In the sands of time.
    Posts
    13

    Resolved Re: Good ol' Blackjack Project

    I've got it working how I need it! Thank you all for your help! I would post it, but it's probably not up to standards as I did use what was suggested, but otherwise... it's a long one.

  8. #8
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    110,344

    Re: [RESOLVED] Good ol' Blackjack Project

    So you know, it's bad practice to access the same property of My.Resources over and over the way you are. That's because those properties don't just hold data like most do but actually extract the resource from the EXE each time. That means that if you access the property N times you will get N objects that are all identical but distinct. In the case of Images especially, that's a bad thing. A better idea is to declare fields for the Images and assign the resource properties to them once, then use the fields repeatedly.

  9. #9
    You don't want to know.
    Join Date
    Aug 2010
    Posts
    4,578

    Re: Good ol' Blackjack Project

    Quote Originally Posted by Shaggy Hiker View Post
    I'm not quite sure why Sitten felt that "a dictionary associating a card with an image" wouldn't work, because both the image and the card would be unique, so either one could be the key, as far as I can see. I'm not sure that you'd want to do that, but it seems like you could have a card as the key and the image as the value, or vice versa.
    I got a bite!

    These two Cards are not equal in a way that will make Dictionary consider them the same key:
    Dim twoOfClubs As New Card() With { .Value = 2, .Suit = Suit.Clubs }
    Dim deuceOfClubs As New Card() With { .Value = 2, .Suit = Suit.Clubs }
    To get THAT, you need to implement IEquatable. Or use value tuples instead of classes, but they're not quite as full-featured in VB as they are in C#.
    This answer is wrong. You should be using TableAdapter and Dictionaries instead.

  10. #10
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    39,039

    Re: [RESOLVED] Good ol' Blackjack Project

    What the deuce are you talking about?

    (best pun I could make of that on the spur of the moment)

    I agree that those two are not equal in a way that will make Dictionary consider them the same key, but I also don't see anything wrong with that. I would be making up 52 Card objects. Those would, and should, be unique. Whether you call a two a deuce, or not, seems like something for an override of .ToString.
    My usual boring signature: Nothing

  11. #11
    You don't want to know.
    Join Date
    Aug 2010
    Posts
    4,578

    Re: [RESOLVED] Good ol' Blackjack Project

    It's easier to explain why this matters in terms of VB code than English.
    Code:
    Module Module1
    
        Sub Main()
            Dim twoOfClubs As New Card With {.Id = 0}
            Dim twoOfClubsImage As New Image With {.Name = "Two of Clubs"}
    
            Dim imageLookup As New Dictionary(Of Card, Image) From {
                {twoOfClubs, twoOfClubsImage}
            }
    
            Dim anotherTwoOfClubs As New Card With {.Id = 0}
    
            Dim theImage As Image = Nothing
            If imageLookup.TryGetValue(anotherTwoOfClubs, theImage) Then
                Console.WriteLine("Found image with name {0}", theImage.Name)
            Else
                Console.WriteLine("This is why it matters.")
            End If
    
        End Sub
    
    End Module
    
    Public Class Card
        Public Property Id As Integer
    End Class
    
    Public Class Image
        Public Property Name As String
    End Class
    Without IEquatable implemented, the Dictionary is going to use Object.Equals(), which is reference equality by default. The two cards are not the "same", so you can't fetch the image for "Two of Clubs" without having the identical card from when you created it.

    Several solutions exist. You could make Card implement IEquatable. It turns out value tuples implement that from the start:
    Code:
    Module Module1
    
        Sub Main()
            Dim twoOfClubs = (Value:=2, Suit:=Suit.Clubs)
            Dim twoOfClubsImage As New Image With {.Name = "Two of Clubs"}
    
            Dim imageLookup As New Dictionary(Of ValueTuple(Of Integer, Suit), Image) From {
                {twoOfClubs, twoOfClubsImage}
            }
    
            Dim anotherTwoOfClubs = (Value:=2, Suit:=Suit.Clubs)
    
            Dim theImage As Image = Nothing
            If imageLookup.TryGetValue(anotherTwoOfClubs, theImage) Then
                Console.WriteLine("Found image with name {0}", theImage.Name)
            Else
                Console.WriteLine("This is why it matters.")
            End If
    
        End Sub
    
    End Module
    
    Public Enum Suit
        Hearts
        Diamonds
        Clubs
        Spades
    End Enum
    
    Public Class Image
        Public Property Name As String
    End Class
    Or you might just choose to give Card an Image property, but then you still have to write SOMETHING to conveniently fetch a specific card!

    There are lots of ways to go about solving the problem, most of them are pretty good. You're probably arguing from the angle, "If I'm writing a card game, then I'll just make one instance of "two of clubs" ever, so I don't need to use a lookup."

    Now imagine extending that to a Blackjack game that shuffles in 2 decks. It's a little trickier to simulate 2 decks with only 1 "deck" of cards in-memory. Much more convenient to implement 2 decks with 2 decks. (But again, there's plenty of other elegant solutions to the problem.)

    I'm the kind of dork that would expand either of the above examples so I can create a "card" this way:
    Code:
    Dim twoOfClubs = 2.OfClubs()
    This answer is wrong. You should be using TableAdapter and Dictionaries instead.

  12. #12
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    39,039

    Re: [RESOLVED] Good ol' Blackjack Project

    Yeah, that was my position. I don't play those multi-deck games, so if I see more than one two of clubs...then somebody is cheating....very poorly (if you are going to add a card, why add a two?).
    My usual boring signature: Nothing

  13. #13
    You don't want to know.
    Join Date
    Aug 2010
    Posts
    4,578

    Re: [RESOLVED] Good ol' Blackjack Project

    Because:

    Name:  30.jpg
Views: 418
Size:  67.4 KB
    This answer is wrong. You should be using TableAdapter and Dictionaries instead.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width