A Game of Memory in VB.NET

Game of MemoryOne of the first projects that someone new to programming often wants to do is a game. Often times they want to do something they have seen on their consoles or mega computer games without realizing how much work actually goes into designing and implementing a game of that scope. After reading a book about programming they realize how tough those games are and that games of that scope usually involve dozens of programmers as well as designers, writers, production and marketing people as well. But does that mean you have to learn boring “Hello World” programs for the rest of your career? Certainly not. We will show you how to get started with learning how to build a simple game that can also be fun and teach you a few programming principles along the way. We will create a small instance of the game “Memory” in VB.NET. It is visual and not too complicated, but fun and can be expanded to include even more features.

How does the game of Memory work?

The game of Memory (also known as Concentration), for those who have not heard of it before, is a game where the player is presented with several playing cards all face down and randomly mixed up. The player must then choose 2 cards (traditionally) and flip them over to see if they match. If they match, they are left face up and the player chooses another set to make a match. If the cards do not match, the player attempts to remember what they look like before flipping them face down again. The game is over when all the cards have been matched and thus are face up. How fast can you make all the matches?

A way to implement the game

To start off building this game we are going to identify some major components of the game mechanics. These include:

  1. A list of graphics which will act as our card faces and the background of the card. For this we will use a standard image list control. We will store 5 card images (Ace, King, Queen, Jack and Joker) and one background graphic which will represent the back of the cards.
  2. We need another list to store the currently chosen “flipped over” cards. If we are looking for 2 cards to match, this list will be 2 in length. If we are looking for three cards to match, it will be 3 in length. Once the proper number of cards have been chosen, we will loop through the cards and see if they all match. Whether they match or not, we are going to clear this list before letting the user choose more cards.
  3. We will need another list to store the matches. Whenever a match is made we will store the match in this list. This will let us know if that match has already been found. We will use this list to make sure that no card that has been matched can be selected again.
  4. Flipping a card over. This is an event that the player generates when selecting a card that has not been flipped before. They click a face down card, it triggers an event that will see if the card has already been matched. If it has not been matched, we add it to our flipped over card list, evaluate the list to see if it meets the length of cards needed for a match (did they select 2 cards in a game that requires 2 cards to match?) and then checks to see if they match. Of course if they don’t match, we are going to flip them back over again, clear the chosen cards list and move on with the game.
  5. Setup a new game. This is going to clear all of our previous lists (if they had anything in them) and then setup a new list of cards (using the images from the image list) and randomize them. We then delete any cards on the screen and replace them again. This will start us off fresh.

The code for implementing the game

First we will need to setup our lists of pictureboxes and other private variables to keep track of cards, matches, selected cards etc.

Private Choices As New List(Of PictureBox)
Private Cards As New List(Of PictureBox)
Private Matches As New List(Of Integer)
Private CopiesOfCard As Integer

The second part is setting up the new game. Again we are going to clear any of our lists, setup a new list of card images and randomize them using a shuffle algorithm. We then display them to screen. The key part of this code to focus on is the loop. Each card we are going to represent as a picturebox. We create a list of pictureboxes, set their image to the face down image, tag them with the type of card they are (so we can easily compare cards later to see if they match) and lastly attach an event to them for when the user clicks the picturebox to flip it over.

Private Sub SetupCards(howManyCardTypes As Integer, numberOfCopiesPerCard As Integer)
        ' Start by calculating the number of cards that will be displayed. This is number of card variations times copies per card.
        ' Resize our cards array to fit all these cards.

        CopiesOfCard = numberOfCopiesPerCard

        ' Clear any existing game data
        ClearGame()

        ' Image list index keeps track of which card we are working with from the image list control
        Dim imageListIndex As Integer = 0

        ' Fill our cards picturebox list making sure to put in the appropriate copies of each card
        ' We then step that many copies on each iteration of outer loop. e.g. If we have three copies, we start at zero index and skip to 3 index on next iteration.
        Dim length As Integer = numberOfCopiesPerCard * howManyCardTypes

        For i As Integer = 0 To length - 1 Step numberOfCopiesPerCard

            ' Makes copies of each card and tag each card with the index from the image list
            For j As Integer = 1 To numberOfCopiesPerCard
                Dim picCard As PictureBox = New PictureBox()
                picCard.Image = imgListCards.Images(imgListCards.Images.Count - 1)
                picCard.Tag = imageListIndex
                AddHandler picCard.Click, AddressOf Me.cardflip_click

                Cards.Add(picCard)
            Next

            imageListIndex += 1
        Next

        ' We call to shuffle the cards
        Shuffle(Cards)

        ' Then display the cards with 5 per line
        DisplayCards(5)

End Sub

We built in some functionality to this method so that we can customize the game. We can specify how many copies of each card are going to be on the board (and thus the number of cards the player will need to click to make a match) and how many card types we will use. So calling SetupGame(5,3) is going to say we have 5 card types and each will have 3 copies on the board. The player then has to click 3 cards to make a match.

The third step will be the event for when someone clicks a card. We have to evaluate if a match has occurred, if that card has already been found as a match and set the image of the picturebox based on the stored “tag”. The tag itself is an integer that represents the card type like 0 = Ace and 1 = King etc. We use this integer to then find the number as an index for the image list control and set the image of the picturebox. Then we clean up our lists (or add to lists) as needed depending on if a match was made or not.

''' <summary>
''' Event for showing a card and evaluating it for matches.
''' </summary>
''' <param name="sender">Presumably the picturebox card that was clicked.</param>
''' <param name="e">Eventargs</param>
Private Sub cardflip_click(sender As Object, e As EventArgs)
        Dim picture As PictureBox = CType(sender, PictureBox)
        Dim idTag As Integer = CType(picture.Tag, Integer)

        If Not Choices.Contains(picture) And Not Matches.Contains(idTag) Then
            Choices.Add(picture)
            ShowCard(picture)

            If Choices.Count = CopiesOfCard Then
                If ChoicesMatch() Then
                    statusLabel.Text = "You found a match!"
                    Matches.Add(idTag)
                Else
                    statusLabel.Text = "No match, sorry!"
                    Threading.Thread.Sleep(1000)

                    ' Hide the choices the user made
                    For i As Integer = 0 To Choices.Count - 1
                        HideCard(Choices(i))
                    Next
                End If

                ' Clear the choices (match or no match)
                Choices.Clear()
            End If
        End If
End Sub

In the code above you might be wondering what the thread sleep is all about. Well, to prevent the game from hiding the cards immediately after determining no match was made, we pause the game for a second and then proceed with flipping them back over. If you wanted to make this more or less challenging, you could reduce/increase the time the player has to look at the card. Once the time expires we go about covering up all the chosen cards.

Next comes our small support helper functions. Ones to hide or show a card, to clear the game lists (used during a new game setup), shuffle the cards and determine if a match happens. For shuffling we will use the Fisher-Yates algorithm and determining a match is just looping through the chosen cards and seeing if all the tags match. If they don’t match at any point we know they don’t have all matches.


''' <summary>
''' ClearGame handles clearing the cards, choices and board.
''' </summary>
Private Sub ClearGame()
        If Cards.Count > 0 Then
            For i As Integer = 0 To Cards.Count - 1
                Me.Controls.Remove(Cards(i))
            Next
        End If

        ' Clear the cards if they were already setup from a previous game.
        Cards.Clear()
        Choices.Clear()
        Matches.Clear()
End Sub

''' <summary>
''' Checks to make sure that all chosen items match successfully
''' </summary>
''' <returns>True or False</returns>
Private Function ChoicesMatch() As Boolean
        For i As Integer = 1 To Choices.Count - 1
            Dim c1 As Integer = CType(Choices(i - 1).Tag, Integer)
            Dim c2 As Integer = CType(Choices(i).Tag, Integer)

            If c1 <> c2 Then
                Return False
            End If
        Next

        Return True
End Function


Private Sub ShowCard(card As PictureBox)
        card.Image = imgListCards.Images(Convert.ToInt32(card.Tag))
        Me.Refresh()
End Sub

Private Sub HideCard(card As PictureBox)
        card.Image = imgListCards.Images(imgListCards.Images.Count - 1)
End Sub


''' <summary>
''' Shuffles picturebox controls around randomly using the Fisher-Yates algorithm
''' </summary>
''' <param name="cards">Array of PictureBox Controls to shuffle</param>
Private Sub Shuffle(ByRef cards As List(Of PictureBox))
        Dim r As Random = New Random()
        For i = 0 To cards.Count - 1
            Dim index As Integer = r.Next(i, cards.Count)

            ' Do a simple swap here
            If i <> index Then
                Dim temp As PictureBox = cards(i)
                cards(i) = cards(index)
                cards(index) = temp
            End If
        Next
End Sub

''' <summary>
''' Display the cards to the screen, broken into number of cards per line.
''' </summary>
''' <param name="cardsPerLine">The number of cards to have per line</param>
''' <remarks>Cards per line should be greater than zero.</remarks>
Private Sub DisplayCards(cardsPerLine As Integer)
        Dim startX As Integer = 15
        Dim startY As Integer = 50

        For i As Integer = 0 To Cards.Count - 1
            Cards(i).Top = startY
            Cards(i).Left = startX
            Cards(i).Size = New System.Drawing.Size(100, 146)
            Me.Controls.Add(Cards(i))

            Cards(i).Visible = True

            startX = startX + 120

            If (i + 1) Mod cardsPerLine = 0 Then
                startX = 15
                startY = startY + 166
            End If
        Next
End Sub

Another major piece here is the displaying of the cards. We need to loop through the cards and place them onto the form at a specified width/height and at a specified X/Y coordinate. For a bit of extra added functionality, we take in a parameter that determines how many cards we should display on a given row. By default above we give it 5 so there are 5 cards on each row but you can really specify any number given that it is greater than 1 and less than the number of cards we have in this run of the game.

''' <summary>
''' Event for showing a card and evaluating it for matches.
''' </summary>
''' <param name="sender">Presumably the picturebox card that was clicked.</param>
''' <param name="e">Eventargs</param>
Private Sub cardflip_click(sender As Object, e As EventArgs)
        Dim picture As PictureBox = CType(sender, PictureBox)
        Dim idTag As Integer = CType(picture.Tag, Integer)

        If Not Choices.Contains(picture) And Not Matches.Contains(idTag) Then
            Choices.Add(picture)
            ShowCard(picture)

            If Choices.Count = CopiesOfCard Then
                If ChoicesMatch() Then
                    statusLabel.Text = "You found a match!"
                    Matches.Add(idTag)
                Else
                    statusLabel.Text = "No match, sorry!"
                    Threading.Thread.Sleep(1000)

                    ' Hide the choices the user made
                    For i As Integer = 0 To Choices.Count - 1
                        HideCard(Choices(i))
                    Next
                End If

                ' Clear the choices (match or no match)
                Choices.Clear()
            End If
        End If
End Sub

The last thing we need to do is have a mechanism to select a game setup. We did this using a few menu choices in a menustrip. In the menu we provided two game types. One game requires 2 matches and the other requires 3 game matches.

' Menu toolstrip items for configuring the game in different ways and for exiting
Private Sub TwoMatchesToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles TwoMatchesToolStripMenuItem.Click
        SetupCards(5, 2)
End Sub

Private Sub ThreeMatchesToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles ThreeMatchesToolStripMenuItem.Click
        SetupCards(5, 3)
End Sub

So how does this thing look?

To give you some screenshots of how this game looks (along with some assets you can use for your game) see the images and links below.

Game of Memory Screenshot 1

Game of Memory Screenshot 2

Click here to download the images I used for the demo above.

You don’t have to have a ton of knowledge to create games or even a whole team working for years to develop a game that people would like. With a little ingenuity, and time, you can create classic games that can turn into something that thousands of people will love. Some ideas you could use to expand this game would be to play someone online where the winner is the one with the most matches, you could add in some card flipping animation or even allow the player to select their own card themes.

All the code in this blog is in the public domain and feel free to steal what you want and implement it in your own game projects. Thanks for reading! 🙂

About The Author

Martyr2 is the founder of the Coders Lexicon and author of the new ebooks "The Programmers Idea Book" and "Diagnosing the Problem" . He has been a programmer for over 25 years. He works for a hot application development company in Vancouver Canada which service some of the biggest tech companies in the world. He has won numerous awards for his mentoring in software development and contributes regularly to several communities around the web. He is an expert in numerous languages including .NET, PHP, C/C++, Java and more.