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:
- Extremely dynamic with respect to the number of rows and the size of each individual cell.
- Loads image pieces dynamically.
- Scales images to the length of the puzzle.
- 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.
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.
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.
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:
- Destination place should be a valid position to move (no cross movements).
- An image should not allow drag and drop on itself.
- Once checks are done, the images are swapped.
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;
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.
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.