Printer Friendly Version      Send     
Click to Rate and Give Feedback
Related Articles
The goal of the ADO.NET Data Services Framework is to create a simple REST-based framework for exposing and consuming data-centric services easily.

By Elisa Flasko and Mike Flasko (August 2008)
We introduce you to the EDI functionality within BizTalk Server 2006 R2, illustrating schema creation, document mapping, EDI delivery and transmission, and exception handling.

By Mark Beckner (August 2008)
In this excerpt from his upcoming book, Laurence Moroney explains the basics of Silverlight animation and the animation tools available in Expression Blend.

By Lawrence Moroney (August 2008)
We build a Silverlight 2.0 application using the InkPresenter to let users annotate a pre-defined collection of images, perform handwriting recognition, and save the annotations and recognized text into a server-side database.

By Julia Lerman (August 2008)
More ...
Articles by this Author
IntroducingOn10.net (http://on10.net), the Channel 9 answer for the technology enthusiast who isn’t necessarily a programmer.

By Duncan Mackenzie (December 2006)
The My Namespace is best described as a speed-dial for the .NET Framework. It provides an intuitive navigation hierarchy that exposes existing .NET functionality through easily understood root objects. Here Duncan Mackenzie explains it all.

By Duncan Mackenzie (Visual Studio 2005 Guided Tour 2006)
Hansel and Gretel had the right idea when "they followed the pebbles that glistened there like newly minted coins, showing them the way. " The deeper you get into the forest or into your data, the more likely you are going to need help to find your way back out again.

By Duncan Mackenzie (July 2005)
Many applications need to store user-specific settings to be persisted between sessions. But how do you go about saving and restoring these settings in your Microsoft® . NET Framework-based application? It's not all that easy to find the correct answer.

By Duncan Mackenzie (April 2005)
I have to admit it; most of my Windows® Forms controls are an attempt to copy something that already exists. In my October 2004 column I showed you how to create a progress bar that mimicked the one shown during the Windows XP setup routine, and this month I'm at it again.

By Duncan Mackenzie (January 2005)
As a parent of a young child, I take a lot of pictures—many more than anyone would ever be interested in seeing. Well, anyone except my mother. This is her first grandchild and the one or two pictures I send to her each week only brush the surface of her grandmotherly needs.

By Duncan Mackenzie (November 2004)
In many situations, accurately estimating the length of a certain process (copying a large file, loading data from a server, retrieving files from the Internet) would be both difficult and inefficient.

By Duncan Mackenzie (October 2004)


By Duncan Mackenzie (July 2004)
More ...
Popular Articles
Speech Server 2007 lets you create sophisticated voice-response applications with Microsoft .NET Framework and Visual Studio tool integration. Here’s how.

By Michael Dunn (April 2008)
Efficient parallel applications aren’t born by merely running an old app on a parallel processor machine. Tuning needs to be done if you’re to gain maximum benefit.

By Rahul V. Patil and Boby George (June 2008)
Here the author introduces SQL Server Data Services, which exposes its functionality over standard Web service interfaces.

By David Robinson (July 2008)
One-time passwords offer solutions to dictionary attacks, phishing, interception, and lots of other security breaches. Here's how it all works.

By Dan Griffin (May 2008)
More ...
Read the Blog
One of the neat things about XAML is that you can not only declare your objects using an XML syntax, but that you can define transformations to rotate, move, and skew your objects. In the August 2008 issue of MSDN Magazine, in an article adapted from his upcoming book Introducing Microsoft Silverlight ...
Read more!
Microsoft has a long history of introducing new features to shipped products, often under the banner of Power Toys or Power Tools. In the August 2008 issue of MSDN Magazine, Brian Randell takes you on a tour of some useful tools for ...
Read more!
Designing software is often an exercise in managing complexity. You can take steps to limit the complexity of any given class by only assigning it a discrete set of responsibilities, applying a concept known as object role stereotypes. In the August 2008 issue of MSDN Magazine, Jeremy Miller explains ...
Read more!
When you evaluate any new technology, pattern, or strategy, you have to consider how that new piece of the puzzle is going to mesh with your existing application architecture. With the Entity Framework, integration is not a problem. In the July 2008 issue of MSDN Magazine, John Papa demonstrated ...
Read more!
Electronic Document Interchange (EDI) encompasses the largest share of real-world business-to-business commerce—nearly 90 percent of the current market—and is growing rapidly year over year. In the August 2008 issue of MSDN Magazine, Mark Beckner introduces ...
Read more!
Separation of presentation and data is not a new idea, but with the growing popularity of technologies such as AJAX and Silver­light, it has become much more prevalent. ADO.NET Data Services Framework began as a way to help developers looking to expose and consume data via services from their applications.. In the August 2008 issue of MSDN ...
Read more!
More ...
Advanced Basics
A Match-Making Game in Visual Basic
Duncan Mackenzie

Code download available at: AdvancedBasics0510.exe (282 KB)
Browse the Code Online
My four-year-old son has decided that he wants to be like his dad when he grows up. He is planning to work in my office, and write computer programs just like I do. But there is one problem—he thinks I write games. My attempts to explain the complex content publishing systems I work on didn't get very far. It seems that I will have to either get a job in the Xbox® group at Microsoft, or start developing games on the side, so I decided to write a simple game for this column to illustrate some interesting programming concepts. As I looked around at some of my son's favorite games I noticed that he enjoyed playing matching games, so I fired up Visual Basic® and began to write one (see Figure 1).
Figure 1 Cute Matching Game 
It was a great excuse to use GDI+, learn a bit about random number generation, and entertain friends and family. I'll now illustrate the interesting areas of the code and discuss a few very important features that I implemented into the program.
The application is called MatchMaker and, although there is an options window where the user can pick a set of images to use and select other settings, by default it starts up with the most recently used settings. You install the game with a default configuration (with images or sounds that you install along with the program) and then the user can customize the game later. You'll find that game play is straightforward:
  • Click on New Game to start with all the cards flipped over.
  • Click on one card at a time, trying to make matches.
  • If you have one card flipped over and you click on a second card that is a match both cards stay visible for the rest of that game, ignoring any additional clicks.
  • If the two cards do not match, then they flash visible for a few seconds before both flip back over and it is time for you to pick another pair of cards.
  • Once all cards have been matched, the game is over and the time elapsed is displayed on the game's main form.
  • At any time, clicking New Game will reset the playing area and start the game at the beginning again.
  • Clicking on the Options button will let you pick a new folder full of images, change the size of the game board, or change the match/no match sound effects. Note that changing any of the Options will reset your game in progress.
As games go, this is a very simple program, but it has enough complexity that I will need to cover it section by section. To start, let's look at the use of both user-level and application-level settings and the creation of an options dialog box.

Saving and Loading Settings
Earlier I mentioned that you would probably want to ship this game with a set of images and sounds already configured for the user, which is easily handled in an App.config file, so I added one to my project and set up the basic "appSettings" list of key/value pairs (see Figure 2).
It seemed likely that some of the built-in system sounds and images would end up being referenced in this configuration file, so I decided to allow environment variables (such as %windir% or %userprofile%) to be used in these settings. Before using any of these strings in my application, I obtain the proper paths by calling System.Environment.ExpandEnvironmentVariables.
Now, if I planned to use only these settings to control my application, I could just load them up when the main form loads, but instead I want to use them only as defaults if there are no user-defined settings available. I won't go into all the details of how I load and persist user settings, since I covered that information in the April 2005 installment of Advanced Basics, but I did have to customize a bit of that code to support the loading of default settings from the application configuration file. When writing code to load user-defined settings from disk I handle the possibility that there is no settings file by creating a new settings object populated with the values from the application configuration file (see Figure 3).
This means that until the user decides to click on the Options button and make some changes, the defaults will be used every time. If the user does decide to customize his settings, he will be shown the Options dialog, which is displayed modally and allows the user to browse for the appropriate folder or file for the four main settings, as you see in Figure 4.
Figure 4 Choose the Settings 
Each of the first four settings uses a little custom control called the BrowseTextBox, which I created for just this purpose. It combines the Browse button with the textbox control and will create and configure the Open/Save or Folder Browse dialogs as necessary to allow the user to find a file name or directory. The code for this custom control is included in the download for this column along with everything else you need.
If the user clicks OK, then all of the values from this dialog are copied over the current settings, the settings are saved into a user settings file, images are reloaded from the newly specified path, and any game in progress is reset. In the mainline of my application I don't have to worry about whether or not the user has changed any settings, I just call LoadSettings (shown in the code in Figure 3), and I will get the correct values either way. Once I have a path for images, either at start up or after a change in settings, I loop through all of the .bmp, .gif, .jpeg, and .png files in that path and add every valid image that I can load into a collection of Images.
So, through the settings, I have all the information needed to start a game; I found all my images and I know the size of the grid that the game will be played on. The next step is to randomly determine which pictures should be included and to place them randomly on the playing surface.

Making Random Choices
Although Visual Basic .NET includes its own Random number generator (Rnd) and the Microsoft® .NET Framework provides the System.Random class, I prefer to use another random number generator. Within the Cryptographic classes, which make intensive use of random values, there is an RNGCryptoServiceProvider class that can be used to create random numbers within any range you need, without producing any inadvertent patterns that your users might detect while playing the game. To make this class easier to use from the rest of my code, I wrapped the necessary code up into a function that accepts an upper-bound and then returns an integer between 0 and that bound:
Dim realRandom As New RNGCryptoServiceProvider

Private Function GetRndValue(ByVal range As Integer) As Integer
    Dim numb(3) As Byte
    realRandom.GetBytes(numb)
    Return Math.Abs(BitConverter.ToInt32(numb, 0) Mod range)
End Function
The RNGCryptoServiceProvider's GetBytes method takes an array of bytes and fills all of those bytes with random values.
Using the GetRndValue function, I was able to write the most critical aspect of the game, the random choosing of images to place on the board for a game. First, given all the available images (lets call that number n), I have to pick enough images out of that list (randomly) to fill half the spots on the game area (which would be x * y / 2). For each pick I get a random number between 1 and n and then increment that value by 1 repeatedly until I find a value in the full image list that has not yet been used. In the code in Figure 5, imagesToPick is equal to x * y / 2, and imageList.Count-1 is the number of images available.
Once I have my smaller subset of images, I need to put two of each of these images onto the game board. The board is a grid, but for my purposes it is simplest to represent it as a linear array with x * y elements, so I just need to fill up that array with two copies of each of my chosen images:
Dim finalList As ArrayList = CType(orderedImages.Clone(), ArrayList)
For i As Integer = 0 To finalList.Count - 1
    Dim newIndex As Integer = GetRndValue(finalList.Count)
    Dim tmp As Object = finalList(i)
    finalList(i) = list(newIndex)
    finalList(newIndex) = tmp
Next
I simply create a copy of the orderedImages list and then swap each element in the list with a random location in the list, thereby creating a randomly ordered list.

Playing the Game
Given the filled array containing the images for every spot on the game board, I have everything I need to start an actual game. I created a separate control to represent the game board itself, and it handles all the user's clicks, remembers their first and second picks in a turn, and raises events to tell the main form when a match is made, when any card is chosen, and when all the matches have been found. The code within this control, other than for drawing the images themselves, is all about tracking the current state of the game, which includes the current picks and the list of all matches that have already been found.
The control is hardcoded to allow the user to pick only two cards at a time, and since it already has the full list of images to handle the drawing, it is able to compare the two chosen items and determine if the user has made a match. Matches are stored into an integer collection (two entries for each match) that is then used in the drawing code to determine if an image or just the standard "card back" should be drawn.
In the main form, if a match is chosen or if the game is over, a message is displayed and a sound is played, but if the user picks two cards that do not make a match then a bit more complicated response is needed. To make the game work, the user needs to see the two non-matching cards they picked for long enough to have a chance to remember them, and then they both need to be flipped back over. I decided to use a timer for this purpose, currently hardcoded to a three-second interval. I enable the timer and then call the game surface's FlipCardsBackOverroutine when the three seconds are up (see Figure 6).
During the time that the two cards are visible, the game surface ignores the user's clicks (because it still has his last two choices stored into its properties) but the form is still fully functional and the user could click on the New Game or Options buttons. If a player is particularly impatient, that three-second interval might make him wonder when he could make his next move, so I change the cursor to an hourglass in order to make it a bit clearer that he must wait for a moment.

Drawing the Actual Images
Despite the fact that the game is all about showing images, doing so is actually the simplest functionality to implement. Whenever the game surface needs to be painted, all that is required is a loop through the array of images and a check against the list of matches. If a location in the list is in the match collection or if it is one of the user's current guesses (one or two of which can be active at any time) then draw the image, otherwise draw a standard image as a card back (see Figure 7).
If the real image needs to be drawn, then there is a bit of additional code, ResizeImage, to resize it to fit into the area available while still maintaining its proportions, which you'll also see in the download for this column.
Since the OnPaint code knows to display images if they are one of the user's guesses or if they have been matched already, the game surface just needs to be invalidated whenever a match is made or the user picks a card.

Fit and Finish Work
I did not have much time to make this game look polished instead of just functional, but I did have to add some type of audio support. With that in mind, I added support for simple sounds, playing a different sound depending on whether the user makes a match or not. I decided to limit my sound support to .wav files, instead of trying to support more complex sound files such as .wma. This choice meant that I could use the PlaySound API, instead of trying to work with something like Managed DirectX®, simplifying the code and the system requirements for the user (see the code in Figure 8).
This game could certainly use a few additional features, such as a high-score list (for fastest-time in this case), but it does what I wanted—provides a working example of a match-making game with all the code available to you in Visual Basic .NET. Check out the Coding 4 Fun site on MSDN® for more game and graphic-related programming ideas!

Send your questions and comments to  basics@microsoft.com.


Duncan Mackenzie is a developer for MSDN and the author of the Coding 4 Fun column on MSDN online. He can be reached through his personal site at www.duncanmackenzie.net.

© 2008 Microsoft Corporation and CMP Media, LLC. All rights reserved; reproduction in part or in whole without permission is prohibited.
Page view tracker