SILVERLIGHT3 game development of FreeCell Solitaire Basics

Source: Internet
Author: User
Tags silverlight

Description: I am the first part of a FreeCell article I published in IT168 in 2011, and the latter parts are not good to look for. Of course, I mainly focus on learning Microsoft ASP and Silverlight+windows Phone 7 development technology. Moved here for students ' reference only. In addition, attention is directed only to advanced players, and I use random licensing techniques.

In this article, we will discuss the basic programming work in FreeCell game development.

First, define global variables

The key data structures used in this game are listed below:


private int nmaxmovingcards = 13;

DispatcherTimer timer;

Private Card Currentcard;

Private Card Inversecolorcard;

Private Card Secondinversecolorcard;

Private Card Previousmatchedcardinseryatbottom;

Private List topelementlist;

Card Previousmatchedcardincells;


List PlaceHolder;

Card[] Cells=new card[4];

List[] Foundationpiles;

List[] Tableaupiles;

DateTime Timestart;

int zindexforall = 0;

Private Cursor originalcursor;

Private Gameover Gameoverdlg;

Private Movemulticardsdlg Movemulticardsdlg;

Inversecolorclickbehavior[] Inversebehaviorarray;

int iglobalbottomcolumn =-1;

int iGlobalBottomColumn2 =-1;

int iglobalcellscolumn =-1;

The following is an introduction to the roles of these variables respectively.

Nmaxmovingcards: Used to limit the maximum number of poker that can be moved at the bottom.

Timer: A Timer control that controls the total game process.

Currentcard: Used to store the current poker. The current poker is stored in this variable when you click on the upper left or any card in the lower area of the card (except the recycling unit at the top right).

Inversecolorcard: Used to store the current inverse color poker.

Secondinversecolorcard: Used to store the most recent anti-color poker at the bottom of the screen.

Topelementlist: Used to record a valid poker sequence that may exist in the lower part of the screen, and the poker in this sequence will move from one column to another.

Previousmatchedcardinseryatbottom: Used in conjunction with variable topelementlist to mark the first poker in the lower valid sequence.

Cells: A card array that records 4 cards in the right-hand cell area of the upper left of the screen.

Foundationpiles: A list array that records four stacks of poker in the collection unit at the top right of the screen.

Tableaupiles: A list array for recording the lower 8 stacks of poker.

Inversebehaviorarray: An Inversecolorclickbehavior array that is used to correlate to 52 cards for inverse color effects.

The role of several other variables is not to be mentioned here. In the next article, we'll combine the code to describe its role.

  Second, choose to move more than one Poker dialog box

In FreeCell Games, when you may want to move multiple cards, a dialog box will pop up Movemulticardsdlg, as shown in. Depending on the situation, you can choose to move one or more sheets.

Notice that, in the main game screen, there is a set of ordered poker in the lower stack that we just clicked on, and the column currently clicked is empty. A related dialog will pop up prompting you to move one or more cards to this nil. The actual number of mobile poker depends on the total number of available mediation units.

  Third, initialize placeholder

In order to conveniently determine the position of poker, we have also introduced a list of lists called placeholder in this game. We have a total of 16 placeholders defined, and their initialization is implemented in the Initplaceholder method of the game initialization. The main implementation code is as follows:


private void Initplaceholder () {

PlaceHolder = new List (16);

Placeholder.add (New Rect (3 + PADDING, 0 + PADDING, WIDTH, border= "1" Height1));//cell1

...... Omit other

Placeholder.add (New Rect (343 + PADDING, 0 + PADDING, WIDTH, border= "1" Height1));//topright1

...... Omit other

Placeholder.add (New Rect (0 + PADDING, + PADDING, WIDTH, border= "1" Height2));//bottom1

...... Omit other


16 placeholders, 4 corresponding to the upper left of the available cells, 4 corresponding to the upper right of the recycling unit, the remaining 8 corresponds to the lower 8 columns.

Below, we discuss how to use the data structure defined above to generate poker and licensing issues.

  Iv. Generating Poker and licensing

First, the licensing operation is implemented in the Generateanddealcards method.

(1) Generate 52 random sequences of poker

First, 52 cards should be generated in random order:


private void Generateanddealcards () {

card[] Arrpoker = new card[52];

card[] Orderpoker = new card[52];

int[] Randomi = new int[52];

int curnum;

Randomkdiffer (0, Wuyi, Randomi);

for (int i = 0; i < i++) {

Curnum = i < 13? i + 1: ((i + 1)% = = 0?: (i + 1)%);//range 1~13

if (I < 13)//0-12

Orderpoker[i] = new Card (Curnum, suits.clubs);

else if (I < 26)//13-25

Orderpoker[i] = new Card (Curnum,;

else if (I < 39)//26-38

Orderpoker[i] = new Card (Curnum, suits.hearts);


Orderpoker[i] = new Card (Curnum, suits.spades);

Arrpoker[randomi[i]] = orderpoker[i];//disorderly order

Inversebehaviorarray[i]. Attach (Arrpoker[randomi[i]);

...... Omit other


First, we define a card array arrpoker to store 52 random sequences of poker. Another card array, Orderpoker, is used to store 52 cards in order from childhood to large.

Second, with the help of method Randomkdiffer, we generate 52 different poker numbers from 0 to 51.

Next, the 52 cards stored in the array arrpoker are initialized to positive (in fact, there is no face-down in the FreeCell game).

Finally, once a poker is generated, a related inversecolorclickbehavior behavior is attached to it.

(2) Create an initial element in the main game screen

When the player presses the menu "Game"-"Start", the 52 cards at the bottom of the interface are ready. Gives the run-time snapshot at the beginning of the game.

Notice that we added some rectangle controls at the top to decorate the available cells and the recycling unit. Of course, you can also use other strategies, but we have to be aware of some of the "effects" that arise.

Specifically, two of the games involve this "impact". One is the previous discussion of how to get the current poker getcurrentcard. The other is when and how we should add the above rectangle control.

First, we chose to add these rectangles in method Generateanddealcards. However, these rectangles are not visible on the screen until you click the Start menu.

Second, we decided to load these rectangle-related XAML code in a dynamic way before formally loading the poker controls.

So, how to load dynamically? The Loadrectangleelementsfirst method for accomplishing this task is discussed below. The key code for this method is as follows:


private void Loadrectangleelementsfirst () {

XElement rectanglestr = Xelement.parse (


xmlns:x= "Http://"

Fill= "Red" stroke= "Black" border= "1" height= "+" width= "canvas.left=" 308 "" "/>");

CARDCONTAINER.CHILDREN.ADD (Xamlreader.load (rectanglestr. ToString ()) as UIElement);

XElement p3str = Xelement.parse (


xmlns:x= "Http://"

Fill= "White" stretch= "Fill" border= "1" height= "" "width=" 1 "uselayoutrounding=" False "canvas.left=" Data= "M319, l319,8 "stroke=" #FFBEFF00 "/>");

CARDCONTAINER.CHILDREN.ADD (Xamlreader.load (p3str.tostring ()) as UIElement);

XElement p2str = Xelement.parse (


Xmlns= ""

xmlns:x= "Http://"

Fill= "White" stretch= "Fill" stroke= "Black" border= "1" height= "" "width=" 1 "uselayoutrounding=" False "canvas.left=" 0 "Data=" m319,100 l319,8 "/>");

CARDCONTAINER.CHILDREN.ADD (Xamlreader.load (p2str.tostring ()) as UIElement);

...... Omit other

CARDCONTAINER.CHILDREN.ADD (Xamlreader.load (p0_copy6str.tostring ()) as UIElement);


In the above code, the following points are worth noting:

Dynamically create XAML elements using LINQ to XML techniques.

The program must first add a reference to the assembly System.Xml.Linq.dll.

A large number of XElement objects are created and populated with tedious XAML markup.

In each of the XElement objects, you must declare two default XML namespaces; otherwise, we will encounter the following run-time error: Ag_e_parser_missing_default_namespace.

  V. Adding a poker control to a container control

At the beginning of the game, only the lower part of the screen exists poker. Among them, there are 7 randomly generated poker from the top 4 columns on the left, and 6 randomly generated poker in the last 4 columns. The relevant code is as follows:


for (int column = 0; column < 4; column++) {

for (int i = 7 * column; I < 7 * (column + 1); i++) {

Canvas.setleft (Arrpoker[i], (double) placeholder[8 + column]. X);

Canvas.settop (Arrpoker[i], (double) placeholder[8 + column]. Y + large_offset * (i-7 * column));

Tableaupiles[column]. ADD (Arrpoker[i]);




for (int column = 0; column < 4; column++) {

for (int i = 6 * column +; i < 6 * column + i++) {

Canvas.setleft (Arrpoker[i], (double) placeholder[12 + column]. X);

Canvas.settop (Arrpoker[i], (double) placeholder[12 + column]. Y + large_offset * (i-6 * column-28));

Tableaupiles[column + 4]. ADD (Arrpoker[i]);




The above code adds 52 cards of the generated random order to the container control Cardcontainer in two simple two-dimensional foreach loop statements.

  Six, start playing games

Controlling the overall flow of the game through a menu control simplifies programming and makes the program work like a traditional desktop application. The code to start the game looks like this:


private void Menuitem_click (object sender, RoutedEventArgs e) {

string stext = (sender as MenuItem). Menutext.trim ();

Switch (stext) {

Case "Start":

Initandstartgame ();

bstart = true;


... Omit other

Seven, play the game again

As a complete game program, providing replay games is a basic requirement. As the name implies, all data structures should be restored to their original data state before restarting the next game. In fact, there are some tricks in this. On the one hand, recovery depends on the data structure that you use, and on the other hand, recovery depends on where we start the recovery process. The relevant code for the recovery operation used in this game is as follows:


private void Menuitem_click (object sender, RoutedEventArgs e)


string stext = (sender as MenuItem). Menutext.trim ();

Switch (stext) {

Case "Start":

Initandstartgame ();


... Omit other

Here, all the content is ready by calling an assistant method Initandstartgame.

Below, let's look at the main differences in the initialization phase of Solitaire and FreeCell games.


private void Initandstartgame () {

if (timer! = null) {

Timer. Tick-= new EventHandler (Timer_tick);

Timer. Stop ();

timer = null;


Zindexforall = 0;

PlaceHolder = null;

Timer = new DispatcherTimer ();

Timer. Interval = new TimeSpan (0, 0, 1);

Timer. Tick + = new EventHandler (Timer_tick);

Initplaceholder ();

Tableaupiles = null;

Foundationpiles = null;

Tableaupiles = new List[8];

for (int i = 0; i < 8; i++)

Tableaupiles[i] = new List ();

Foundationpiles = new List[4];

for (int i = 0; i < 4; i++)

Foundationpiles [i] = new List ();

Inversebehaviorarray = null;

Inversebehaviorarray = new inversecolorclickbehavior[52];

for (int i = 0; i <; i++)

Inversebehaviorarray[i] = new Inversecolorclickbehavior ();

Generateanddealcards ();

for (int i = 0; i < 4; i++)

Cells[i] = null;

Nmaxmovingcards = 13;


Iglobalbottomcolumn =-1;

IGlobalBottomColumn2 =-1;

Iglobalcellscolumn =-1;

bstart = false;

Timestart = new DateTime ();

Timestart = DateTime.Now;

Timer. Start ();


First, initialize two important structures: Tableaupiles and foundationpiles. Here, we use the data structure tableaupiles to store the 8-column poker at the bottom of the game's main interface, while the data structure Foundationpiles is used to store 4 columns of Poker in the recovery unit.

Next, we create 52 inversecolorclickbehavior types of behavior, which are used to correlate to 52 different poker cards, respectively. Again, in Silverlight programming, a behavior can only be linked to one UI element.

Finally, it should be noted that the subscription to mouse-related events is done in the mainpage_loaded method of the mainpage control, rather than in the Initandstartgame method above, the code is no longer redundant.

This article is from the "Green Peak" blog, please make sure to keep this source

SILVERLIGHT3 game development of FreeCell Solitaire Basics

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.