Published: 21 May 2010
By: Xianzhong Zhu
Download Sample Code

In the two parts of series, we are going to develop another Silverlight 3 based Freecell game like the one shipped with Microsoft Windows. Our main purpose to write this game is to continue to explore the mouse related operations supported in Silverlight 3. And also, in constructing this application you will learn the Silverlight 3-supported behavior related topics.

Contents [hide]

The Developing Freecell Game Using Silverlight 3 Series

  • Developing Freecell Game Using Silverlight 3 Part 1 In the two parts of series, we are going to develop another Silverlight 3 based Freecell game like the one shipped with Microsoft Windows. Our main purpose to write this game is to continue to explore the mouse related operations supported in Silverlight 3. And also, in constructing this application you will learn the Silverlight 3-supported behavior related topics.
  • Developing Freecell Game Using Silverlight 3 Part 2 In this second part of the series, we will delve into the crucial part in the Freecell game. In detail, we are going to examine the two mouse events, i.e. MouseLeftButtonDown and MouseLeftButtonUp, related event handler programming.
  • Introduction

    FreeCell is an extremely addictive solitaire card game invented by Paul Alfille, which is fun and very skill-dependent. It's said in the help documents every game (approximately 99.99 %) of FreeCell solitaire can be won with perfect play. This makes FreeCell card game much more interesting and popular than any of the rest solitaire variations.

    NOTE

    1. The FreeCell game development environments are as follows:

    Windows XP Professional (SP3);

    .NET 3.5 (SP1);

    Visual Studio 2008 Professional (SP1);

    Microsoft Expression Blend 3;

    Microsoft Silverlight Tools for Visual Studio 2008 SP1;

    Part of Windows Presentation Foundation Pixel Shader Effects Library.

    2. You're highly recommended to read the Solitaire game related articles first before reading this series of two articles since we've elided many similar techniques.

    Screen Layout

    FreeCell is a one-deck solitaire card game. All cards are dealt into 8 tableau piles. Four Cells (in the top left corner of the screen) and four foundation piles (top right hand corner) are placed above the tableau piles. Figure 1 indicates the general layout of the FreeCell game.

    Figure 1: The screen layout of the FreeCell game

    The screen layout of the FreeCell game

    Foundation (4 Piles)

    There are four foundation piles in a standard FreeCell game. Base card for foundation cells is Ace, i.e. you have to start building from the Ace of each suits. For example, an a hearts foundation cell will start with Ace of hearts and build 2 to 10, then jack, queen and finally king of hearts.

    Tableau (8 Columns)

    In a standard FreeCell game there are 8 columns of cards. These are called tableau piles. When you create new games you can change this rule and specify your own values. Tableau card arranging order is down in alternating colors, i.e. you have to arrange cards down in order and you have to arrange it in alternating colors. For example, you can put a seven of clubs on top of an eight of hearts because both cards belongs to different suits and they are opposite in color and order by rank. Again, card arranging order in tableau also can be changed for new games.

    Multi move is enabled in the tableau. That is a group of cards can be moved as a group if they are in proper order and there is enough free spaces in tableau or free cells. Multi move can be enabled or disabled for new games.

    Space may be filled with any available card. Again, this also can be changed for new games in the game editor window.

    Free Cells (4 Cells)

    Free Cells or reserve cells are an integral part of FreeCell game and the name FreeCell itself came with this group of cells normally found on the top left of the main game window.

    Free cells are used to store cards temporarily. If there is no possible move in the tableau then you can make use of free cells to store cards. Each cell can hold only one card at a time. Cards in these free cells can be played like any other free cards and can be moved to either foundation or tableau cells.

    Game Rules

    The object of the game is to build up all cards on foundations from Ace to King by following suit. You win when all 52 cards are moved there, 13 to a pile.

    In detail, the rules include:

    • Top cards of tableau piles and cards from Cells are available to play.
    • You can build tableau piles down by alternating color.
    • Only one card at a time can be moved.
    • The top card of any tableau pile can also be moved to any Cell.
    • Each Cell (or Reserve space) may contain only one card.
    • Cards in the cells can be moved to the foundation piles or back to the tableau piles, if possible.

    In addition, the rules state that you can move only one card at a time, but you can move group of cards in the proper sequence if you have enough free (empty) Cells and/or tableau piles.

    Tips

    To try to win the game, you can refer to the following tips:

    • Evaluate the game before making any moves.

    Look for Aces and other low cards that are deeply buried in the columns. Find all those cards and develop a plan to free them before you begin moving cards.

    • Leave as many free (empty) Cells as possible.
    • Try to create an empty tableau as soon as possible. Empty tableau is even better than empty Cell because you can use it to temporarily store (until you need it again) a legal sequence of cards instead of just a single card.
    • Look for plays that organize cards in sequences.

    In the next section, let's introduce the same or similar solutions to the previous Solitaire game in developing the FreeCell game application.

    Same or Similar Solutions to the Solitaire Game

    At first glance, as many readers think, the FreeCell game required techniques quite resemble those in developing the previous Solitaire game application. With a brown study, you may find there are still some knots required to be tackled. How can we support the double click operations (like that in the Windows counterpart) and, at the same time, remain the color inverse characteristic in the FreeCell game? What kind of double click solution are the most appropriate one for the FreeCell game? Having said that, many readers may recall some Adobe Flash based online FreeCell games or other desktop styled ones. Further studying, you found that most of them did not provide the perfect supports like in the Windows built-in version, didn't you? Indeed, I met the similar how-do-you-do in developing the FreeCell application.

    On the other hand, I found that many of the techniques and tips used in my old Solitaire game could be transplanted to write the current FreeCell game. Let's give a brief introduction about them.

    Dealing with the Card Coordinates

    For simplicity, we still select a Canvas control to serve as the parent control of all the card controls. Therefore, we will still fall back on the following functions to deal with the card coordinates:

    Listing 1: The important card coordinates related functions

    Dealing with the Card zIndex

    And also, we'll adopt the same policy as that introduced in the Solitaire game to deal with the z index of each card. I.e. we will continue to use the two methods, GetZIndex and SetZIndex to control the value of the zIndex property of moved cards. For brevity, I want to simply remind readers to notice the following points:

    • By default, all the sub controls in a parent control have the same zIndex property value, i.e. 0. However, due to the characteristics of Silverlight design, the controls with the same zIndex property value still be rendered on the screen in 'different layers'.
    • Considering that there are totally 52 cards and the valid value range for the zIndex property is enough for our game, we can take the action to add 1 to the zIndex property value of current moved card.

    Still Using the Silverlight Menu Control

    In this FreeCell game, we continue to fall back upon the Codeplex supported Silverlight Menu Control to control the overall logic of the game. As pointed out before, to use this Menu control in our game application there are three points deserved your attention, as listed below:

    • You should change the zIndex property value to a large integer (1000 is enough in our case), so that the menu items seem to hover over the other controls on the game screen.
    • When you click a menu item you have to click other areas out of the menu's scope, then you can start your real play.
    • Thanks to the Silverlight menu control, all reset associated things get along as in your familiar desktop applications.

    Mouse Button Related Events

    As first glance, the mouse button handling in the FreeCell game is much simpler than that in the Solitaire game. No dragging and dropping; no mouse capturing. As you will find, what left for us to do is to track the two mouse events, i.e. MouseLeftButtonDown and MouseLeftButtonUp, to decide which card is the current one and which is the previous one. In fact, however, things are not as easy as you will image. All these related programming will be left to be discussed in the second article of the series.

    Non-Double Click Support

    As is known, in the Windows desktop styled FreeCell game, the mouse double click is a good implementation, which accelerates the move of the cards and loved by players. In our case, however, it's pretty difficult to support this solution, which mainly results from the introduction of the InverseColorClickBehavior behavior. By further digging into the how-to, you can easily find the answer - the inner working of the InverseColorClickBehavior behavior has built in another MouseLeftButtonDown event handler which in a large degree encumbers the double click implementation in the outer layer.

    For the above reason, reluctantly, we decide to discard the double click support in the FreeCell game. If you cute readers find other proper double click solutions, please share with us all.

    A Modified Method- GetCurrentCard

    In the FreeCell game, it's also frequently required to locate the current card. So, we have also introduced a method GetCurrentCard to meet this requirement. Please notice that we've adapted the initial version.

    Listing 2: The modified version of the method GetCurrentCard

    Obviously, the main code has not changed, still with the static method FindElementsInHostCoordinates of the VisualTreeHelper class to traverse object relationships in the Silverlight visual tree. Note herein after we removed the parent node from the result set, the judgment condition changes to collidedElements.Count() >1. Why? This is because before we added each Card into the parent Canvas control, we had added some Path objects and Rectangle controls to the parent Canvas control in advance. For this, I remind you of the fact that although the method GetCurrentCard will be commonly-used in your future possible similar game applications like the FreeCell, it's sometime necessary for you to make some modifications to adapt to your new development environment.

    Again, I remind you to pay attention to the argument passed to the method GetPosition (not cardContainer but null) and the second argument passed to the method FindElementsInHostCoordinates is not null but cardContainer.

    Defining a New Card Control

    In the FreeCell game, we've also defined an independent user control- Card - since the general logics are nearly the same as that in the previous Solitaire game. In this case, we only need to define the rank and suit in the Card control since all the cards on the screen are face up. And, without much modification, we'll continue to adopt the similar method to deal with the card related images. That is, the control maintains an Uri array, with each Uri pointing to the corresponding card image. Listing 3 below gives the definition of the Card control.

    Listing 3: The Card control definition

    Different from the Solitaire game, herein we defined just 52 images except for the red Joker and black Joker. We no more need special images to act as placeholders or for special use. To retrieve the related image, we should also resort to the index pointer. And also, to facilitate the instantiating the Card control, we set up another constructor. Altogether, the Card control in this case is much simpler.

    Defining Custom Inverse-color Behavior

    Ever since the release of the Silverlight 3, a lot of new cool features have been introduced. One of the cool features is the support of behaviors and triggers, with which you can declaratively associate an action with an event or property value.

    Why introduce Behaviors?

    From a fundamental point of view, behaviors are pieces of code that a designer can attach to an object simply by dragging and dropping. As you've known, Microsoft Expression Blend 3 has a handful behaviors built in, including the previously-mentioned MouseDragElementBehavior, which you can attach to a UI element to allow it to be dragged with the mouse. They tend to be simple to write, and they do a lot to enhance the power of Expression Blend--and Silverlight, too, for that matter.

    The motivation for adding behaviors in Silverlight 3 is twofold. First, the behaviors are somehow work-around for the missing triggers in Silverlight. They allow closing the gap between WPF and Silverlight. Second, they allow designers to add interactivity without needing to write any code.

    All in all, behavior is nearly a MUST HAVE if you are going to learn Silverlight 3 or higher.

    Developing the InverseColorClickBehavior Behavior

    For simplicity, in this case we select to use the ready-to-use part of Windows Presentation Foundation Pixel Shader Effects Library. However, to adapt to the use of the FreeCell game, we have to make a little modification with the InverseColorClickBehavior behavior.

    Below is the complete code for the custom InverseColorClickBehavior.

    Listing 4: The complete code for the custom InverseColorClickBehavior

    First, as you may notice, the InverseColor typed property inverseColor plays the main role with which we achieve the inverse-color effect of the card. Second, in defining a custom behavior, we usually need to overwrite the two methods, OnAttached and OnDetaching. In the two methods, we usually change the properties or events of the AssociatedObject object. And then, in the related methods you can implement your custom logic to achieve your initial target of developing this custom behavior.

    In the above custom behavior, we are only interested in the AssociatedObject_MouseLeftButtonDown event handler. As you'll know, the AssociatedObject object will refer to the Card control. Based upon the request of the FreeCell game, we just need to control the value of the Effect property. According to the times (odd or even) you click the card, clear or set its Effect property value. In our game, when we set AssociatedObject.Effect to null, the card is deprived of the inverse-color effect; when we set AssociatedObject.Effect to inverseColor, the card wears inverse-color effect.

    Using the InverseColorClickBehavior Behavior

    There is an important characteristic of behavior that you should remember: one behavior can only be attached to one control at a time; one control can be attached to multiple behaviors.

    Let's next look at the concrete leverage of the custom InverseColorClickBehavior behavior.

    First, since we have totally 52 cards we can define the following variable to be used later:

    Second, let's look at the initialization (in the method InitAndStartGame) of the behavior array:

    Third, let's look at the use of these behaviors (within the method GenerateAndDealCards):

    When each card is created, we assign a related behavior attached to the card. Note in our application once the behaviors are bound to the cards we no more care about the related detachments. For more details, you can refer to the source code accompanying this article.

    Designing the Game

    With the game rules in mind, starting from this section we are going to explore all the fundamental work in developing the FreeCell game.

    Defining Global Variables

    Note all the names in Figure 3 refer to the original addressing of the Windows-versioned solitaire game. For simplicity, we only list the most important data structures used in our game, as follows.

    Listing 5: Part of the global variables definitions in our game

    On the whole, the above variables bear the following tasks:

    • nMaxMovingCards: used to limit the maximum number of the pile of cards at the bottom moved onto the matched card at another column at the bottom area.
    • timer: used to control the whole process of the game as well as give other corresponding prompt.
    • CurrentCard: used to hold the current card. Whenever you click any card at the top left or bottom area (except for the top right area) on the screen, the value of the variable is decided.
    • InverseColorCard: used to remember the current inverse-colored card.
    • SecondInverseColorCard: used to remember the most recently inverse-colored card at the bottom area.
    • topElementList: used to remember the possible valid series of cards at the bottom area that will be moved to another column at the bottom.
    • PreviousMatchedCardInSeryAtBottom: in combination with the variable topElementList, used to mark the first card in the valid series at the bottom area.
    • Cells: a Card array used to remember the possible four cards at the top left cells.
    • FoundationPiles: a List<Card> array used to remember the four piles of cards at the top right target area.
    • TableauPiles: a List<Card> array used to remember the eight piles of cards at the bottom area.
    • InverseBehaviorArray: An InverseColorClickBehavior array used to be attached to the fifty-two cards to implement the inverse-color effect.

    For more details about the variables, InverseColorCard, SecondInverseColorCard, PreviousMatchedCardInSeryAtBottom, iGlobalCellsIII, iGlobalBottomColumn, iGlobalBottomColumn2, and iGlobalCellsColumn, you will find their respective use in the second article. Let's next say a few more words about the multiple cards moving dialog.

    A Multiple Cards Moving Related Dialog

    You may have already notice a variable named MoveMultiCardsDlg in the above definitions, which is just relevant to the current topic. In fact, you will also find the related usage in the next article.

    Note the dialog MoveMultiCardsDlg will pop up when we want move one or a group of ordered cards from one column at the bottom area to another empty column. Figure 2 illustrates one of the related snapshots.

    Figure 2: A dialog pops up prompting you to select whether to move one card or more

    A dialog pops up prompting you to select whether to move one card or more

    In Figure 2, the bottom column we previously clicked has a group of ordered cards while the currently-clicked column is empty when a related dialog will pop up prompting you to select whether to move one card or a group of ordered cards. And, of course, the fact number of cards to move will also be decided by empty cells at the top left area.

    Initializing Placeholders

    To facilitate measuring the positions of the cards, we've also introduced a List<Rect> list called PlaceHolder. In this case, there are totally sixteen placeholders defined, which will be initialized in the helper method InitPlaceHolder during the initialization of the game. Listing 6 gives the related code.

    Listing 6: The card placeholders’ initialization

    As you see from the above code, there are totally 16 card placeholders in the main game view, 4 for the cells at the top left, 4 for the foundation piles at the top right, and the rest 8 for the tableau piles at the bottom. Also, note the above eight placeholders have same size while the bottom eight placeholders have a second same size different from the first.

    In the next section, let's look into how to generate and deal cards with the data structures defined above.

    Generating and Dealing Cards

    To start the game, you first have to find some algorithm to deal the card, which is done in the method GenerateAndDealCards.

    Generating 52 Cards in Random Order

    Listing 7 below gives the first part of this method. First of all, you should generate 52 cards in random order.

    Listing 7: Generating 52 cards in random order

    First, we define a Card array arrPoker to hold the final 52 cards in random order. Another Card array OrderPoker is used to store the ordered cards. Second, with the help of the method RandomKDiffer(0, 51, 52, RandomI), we can generate 52 different cards with the index numbers ranging from 0 to 51. Third, the 52 cards stored in array arrPoker are all initialized with face up (in fact none face-down cases are used in the FreeCell game). Last, as soon as each random card is generated a related InverseColorClickBehavior behavior is attached to it. This is one of the important features in the FreeCell game worthy to be noticed.

    Setting up Elementary Scene for the Game

    Please think back to the Windows' FreeCell game--before you press the menu 'Start', there will be some intuitive prompt on the screen. For this, we are also going to ornament the screen with some rectangles. Figure 3 shows the related snapshot.

    Figure 3: The initial state when the game just starts

    The initial state when the game just starts

    As is seen, some rectangles are positioned at the top area to clearly mark the cells and foundation piles area. Of course, you can use whatever controls you image to decorate these areas. Anyway, you have to handle the extra payout. Let's delve into this.

    In our case, there are two points in relation to the payout. One is you have to build up another version of the frequently-used method GetCurrentCard which we've already discussed earlier. The other is when and how we can add those rectangles.

    In fact, in this Silverlight game, to add those rectangles has led to some more trouble.

    First, considering the features of starting and restarting the game, we decide to add those rectangles inside the method GenerateAndDealCards. For this, we cannot gain the effect that before you press the menu 'Start' some intuitive prompt ornaments appear on the screen.

    Second, we decide to load the rectangles related xaml code dynamically just before loading the cards. Then, how to dynamically load this xaml code? Is there anything to be noticed? All of this is finished in the method LoadRectangleElementsFirst, as listed below.

    Listing 8: The key parts of code of the method LoadRectangleElementsFirst

    In the above code, there are the following key points deserving your attention:

    • We create dynamic XAML elements with LINQ to XML technique.
    • We should first add the assembly reference to the System.Xml.Linq.dll.
    • We create many XElement objects and populate it with detailed XAML information.
    • In each of the XElement object related string, you must declare the two default XML namespace; or else, you will see the following alike error: AG_E_PARSER_MISSING_DEFAULT_NAMESPACE.

    In the next section, let's see how to add cards to the parent container.

    Adding Cards to the Parent Container

    At the very beginning of the game, there are only the tableau piles having cards, i.e. each of the first four columns has seven cards while each of the rest four columns has six cards.

    In contrast to the previous Solitaire game, the case in the FreeCell game is much simpler. For brevity, let's directly look at the related code.

    Listing 9: Adding cards to the parent container

    Easily seen, two double for loops bear two tasks respectively: the first sets up the first four columns; the second fills the second four columns. It's not necessary to give detailed explanation; you can refer to the previous Solitaire game related articles.

    Starting the Game

    Everything getting ready, let's look at how to launch the game. In fact, this is pretty simple, part of which owes to the introducing of the MenuControl control. Below indicates the related code.

    Listing 10: Click Start menu item to launch the game

    Next, let's look at another necessary work when the game is over - restore the environment and restart the game.

    Replaying the Game

    In this section, let's check out what are the differences between this FreeCell game and the previous Solitaire game in terms of replaying the game. In fact, they are nearly the same as far as the implementation logic is concerned.

    As a complete game application, it should provide the support for replaying the game. As the name implies, before restarting the game we should reset all required data structures to their original values or states. It, in fact, is not as easy as it seems to have all data restored. On the one hand, the resetting work relies upon what kinds of data structures you introduced; on the other hand, it depends on where you launch the resetting action.

    Listing 11 below shows the game restart related code in this FreeCell game.

    Listing 11: Code for starting or restarting the game

    By invoking the only helper method InitAndStartGame, you get everything ready to play the game. Now, let's continue to follow up the scent to see the differences in the initialization programming.

    Listing 12: Code for the helper method InitAndStartGame

    First, compared with the initialization implementation in the Solitaire game, we initialized two important structures, TableauPiles and FoundationPiles. In this case, the data structure TableauPiles is used to hold eight columns of cards at the bottom area, while another one FoundationPiles is used to hold four columns of cards at the top right area.

    Second, we set up fifty-two InverseColorClickBehavior typed behaviors, which are used to be attached to the initial fifty-two cards respectively. As a general rule, as is already pointed out above, in Silverlight programming field one behavior can only be attached to one UI element at a time.

    Last, as done in the previous Solitaire game, we still have to subscribe to the mouse related events at the Loaded event handler of the MainPage control.

    Listing 13: Code for registering the mouse events

    As emphasized before, we do not need to un-register the mouse events and register them again when we want to replay the game. And also, we have to subscribe to the two events herein rather than in the helper method InitAndStartGame to avoid unexpected things happen.

    Note

    In the current version of the FreeCell game, we have not programmed the MouseMove event handler. In the counterpart of the Windows version, if you click some card and move mouse over the screen, then if there is a card matching the current clicked card at the right area the matched card is located at the mouse cursor will change accordingly to give a more intuitive guide. Due to various reasons, we've not accomplished this support. You can supplement this function yourselves.

    Summary

    In this first part of the series, we've introduced the main skills used to develop the Silverlight based FreeCell game. Note that since many of the techniques are similar to that used in the previous Solitaire game, we discarded the detailed discussion about them. Therefore, for more details about the related implementations, you can refer to the articles introducing the Solitaire game. In the next part of the series, we'll continue to explore the rest and core part of the FreeCell game, i.e. the two mouse events (MouseLeftButtonDown and MouseLeftButtonUp) related programming.

    <<  Previous Article Continue reading and see our next or previous articles Next Article >>

    About Xianzhong Zhu

    I'm a college teacher and also a freelance developer and writer from WeiFang China, with more than fourteen years of experience in design, and development of various kinds of products and applications on Windows platform. My expertise is in Visual C++/Basic/C#, SQL Server 2000/2005/2008, PHP+MyS...

    This author has published 81 articles on DotNetSlackers. View other articles or the complete profile here.

    Other articles in this category


    Displaying Notification Messages in a Silverlight Dashboard Application
    In this article we will see how we could display a notification message and further a list of notifi...
    Air Space Issue in Web Browser Control in Silverlight
    Air Space issue is a common issue in Web Browser control in Silverlight and WPF. To explain the issu...
    TextBox Row Filter in Telerik's RadGridView in Silverlight
    If you have come across the JQGrid features, you might have seen the filter row available as the fir...
    Widget Refresh Timer in MVVM in Silverlight
    In this article we'll see how to refresh and disable widgets using the Model View View-Model pattern...
    Develop a Flexible 2.5D Scene Editor Targeting Silverlight RPG Games - Part 2
    In this article, I'm going to introduce to you how to construct such a 2.5D RPG game scene editor th...

    You might also be interested in the following related blog posts


    Introducing SharePoint 2010 Training at U2U read more
    Silverlight MVP read more
    Building a Silverlight 3 based RIA Image Magagement System (1) read more
    Building a Silverlight 3 based RIA Image Management System - 1 read more
    Telerik Launches RadControls for Silverlight 3 for Line-of-Business Application Development read more
    Why Embedded Silverlight Makes Sense read more
    Telerik Announces Support for Microsoft Silverlight 3 read more
    Win a Govie Award Submit an Innovative Gov 2.0 Application read more
    VideoWiki - Step 0 read more
    Moonlight 1.0 Released, Silverlight script updated – and a Chrome hack read more
    Top
     
     
     

    Please login to rate or to leave a comment.