Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#3.5

Dynamic Sliding Puzzle Generator

4.67/5 (3 votes)
27 Mar 2011CC (Attr 3U)2 min read 42.4K   2.4K  
A dynamic sliding puzzle generator involving LINQ and photo scaling functionalities.

Image 1 Image 2

Introduction

As per Wiki, a sliding puzzle, sliding block puzzle, or sliding tile puzzle challenges a player to slide usually flat pieces along certain routes (usually on a board) to establish a certain end-configuration. But here I would go for a simple (programmatically complex) prototype of sliding puzzle where the players have the flexibility to generate a puzzle from an image of their choice.

Background

Of late, I have been going through various ways of implementing the sliding puzzle (in fact, there are numerous ways even). This version of game here is pretty simple and very dynamic in nature. Each and every line here is written in such a way that the user has complete flexibility to set the size of the individual pieces of a picture as well as the number of cells per row.

The key features in implementing the game are:

  1. Extremely dynamic with respect to the number of rows and the size of each individual cell.
  2. Loads image pieces dynamically.
  3. Scales images to the length of the puzzle.
  4. Uses events to implement the logic.

Using the code

The logic here is to construct and add images dynamically to the Windows form. The function AssignEventsToButtons() does the core functionality of this.

C#
private void AssignEventsToButtons()
{
    PictureBox temp = null;
    int x = -1;
    for (int i = 0; i <= MaxSeed; i++)
    {
         temp = new PictureBox
                {
                   TabIndex = ++x,
                   SizeMode = System.Windows.Forms.PictureBoxSizeMode.CenterImage,
                   Size = new System.Drawing.Size(SideLength, SideLength),
                   Name = string.Concat("pictureBox", x.ToString()),
                   AllowDrop = true,
                   Location = new Point(0, 0)
                };
        
        temp.MouseDown += new MouseEventHandler(button_MouseDown);
        temp.DragDrop += new DragEventHandler(button_DragDrop);
        temp.DragEnter += new DragEventHandler(button_DragEnter);
        temp.CreateControl();
        flowLayoutPanel1.Controls.Add(temp);
    }
    
    flowLayoutPanel1.Controls.Add(this.groupBox1);
    flowLayoutPanel1.PerformLayout();
}

Handling mouse events is crucial here. Every piece of block has to be handling all the three events, namely MouseDown, DragDrop, and DragEnter. Initially consider a piece to be moved to white space, the mouse down event of the current piece is handled to send the picture forward.

C#
private void button_MouseDown(object sender, MouseEventArgs e)
{
    Cursor = Cursors.Hand;
    _dragSource = (PictureBox)sender;
    _dragSource.DoDragDrop(_dragSource.Image, 
                DragDropEffects.Copy | DragDropEffects.Move);
}

The event DragEnter is basically to handle the desired effect of moving the picture.

C#
private void button_DragEnter(object sender, DragEventArgs e)
{
    e.Effect = e.Data.GetDataPresent(DataFormats.Bitmap) ? 
                         DragDropEffects.Move : DragDropEffects.None;
}

The logic part of the game is to check for a valid move. The dragging piece's information is stored and is compared with the destination piece's, with the following steps:

  1. Destination place should be a valid position to move (no cross movements).
  2. An image should not allow drag and drop on itself.
  3. Once checks are done, the images are swapped.
C#
private void button_DragDrop(object sender , DragEventArgs e)
{
    var dest = (PictureBox) sender;

    if(dest.Image.Equals(_dragSource.Image))
        return;

    if( !new List<int>
             {
                 _dragSource.TabIndex + 1,
                 _dragSource.TabIndex - 1,
                 _dragSource.TabIndex + RowCount,
                 _dragSource.TabIndex - RowCount
             }.Contains(dest.TabIndex))
    {
        MessageBox.Show(Resources.DynPuzzleform_button_DragDrop_Invalid_move);
        return;
    }
    
    if (!ImageCompareArray(dest.Image as Bitmap,Resources._17))
    {
        MessageBox.Show(Resources.DynPuzzleform_button_DragDrop_Invalid_move);
        return;
    }

    _dragSource.Image = dest.Image;
    dest.Image = e.Data.GetData(DataFormats.Bitmap) as Image;

    //checks state
    CheckState(_dragSource.TabIndex, dest.TabIndex);
}

Here the function CheckState checks for the state of the game on every step, and is checked with _successState so as to confirm the game's completion. Another interesting feature in this game can be seen when you press F3. Yes, you can load an image of your choice. The image is scaled down to the size the player configured, without distortion. The ResizeImage function does this for you.

Image 3

Note: Check for the settings SideLength and RowCount in DynSlidingPuzzle.exe.config. Please assign valid values for the same.

Conclusion

This concludes the making of a simple yet dynamic game application that demonstrates the ease of using .NET. Please go through the code and let me know your comments. Thanks in advance.

License

This article, along with any associated source code and files, is licensed under The Creative Commons Attribution 3.0 Unported License