|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
|
Announcements
Want a new Job?
Chapters
Services
Feature Zones
|
Note: This is an unedited contribution. If this article is inappropriate,
needs attention or copies someone else's work without reference then please
Report This Article
IntroductionThis is a very simple article that really just demonstrates the various capabilities
of the WPF Where 1 square was blank, and the image portions in the other 8 squares were randomly scattered, and you had to try and recreate the whole image, by sliding the image portion squares into the blank space, and repeating this until you had the whole image again. In a nutshell thats all this article does. So How Does It WorkWell its based in WPF land, so we can use a convienient layout manager called
a And that's exactly what we do. The basic steps are as follows:
Thats all there is to it. So let's look at each of these steps in a bit more detail Step1 : Load An ImageLoading an image is done by the button click event that allows the user to grab a new image, the code is as follows: Microsoft.Win32.OpenFileDialog ofd = new Microsoft.Win32.OpenFileDialog();
ofd.Filter = "Image Files(*.BMP;*.JPG;*.GIF;*.PNG)|*.BMP;*.JPG;*.GIF;*.PNG" +
"|All Files (*.*)|*.*";
ofd.Multiselect = false;
if (ofd.ShowDialog() == true)
{
try
{
image = new BitmapImage(new Uri(ofd.FileName, UriKind.RelativeOrAbsolute));
img = new Image { Source = image };
CreatePuzzleForImage();
}
catch
{
MessageBox.Show("Couldnt load the image file " + ofd.FileName);
}
}
Step2 : Split The Image Into Equals PortionsWe need to grab sequential portions of the original image, but only grab 8, as we need the 9th square to be a blank. So this is done using the following code: //row0
CreateImagePart(0, 0, 0.33333, 0.33333);
CreateImagePart(0.33333, 0, 0.33333, 0.33333);
CreateImagePart(0.66666, 0, 0.33333, 0.33333);
//row1
CreateImagePart(0, 0.33333, 0.33333, 0.33333);
CreateImagePart(0.33333, 0.33333, 0.33333, 0.33333);
CreateImagePart(0.66666, 0.33333, 0.33333, 0.33333);
//row2
CreateImagePart(0, 0.66666, 0.33333, 0.33333);
CreateImagePart(0.33333, 0.66666, 0.33333, 0.33333);
Where the CreateImagePart() method looks like the following: private void CreateImagePart(double x, double y, double width, double height)
{
ImageBrush ib = new ImageBrush();
ib.Stretch = Stretch.UniformToFill;
ib.ImageSource = image;
ib.Viewport = new Rect(0, 0, 1.0, 1.0);
//grab image portion
ib.Viewbox = new Rect(x, y, width, height);
ib.ViewboxUnits = BrushMappingMode.RelativeToBoundingBox;
ib.TileMode = TileMode.None;
Rectangle rectPart = new Rectangle();
rectPart.Fill = ib;
rectPart.Margin = new Thickness(0);
rectPart.HorizontalAlignment = HorizontalAlignment.Stretch;
rectPart.VerticalAlignment = VerticalAlignment.Stretch;
rectPart.MouseDown += new MouseButtonEventHandler(rectPart_MouseDown);
initialUnallocatedParts.Add(rectPart);
}
The most important parts of this is the line that sets the The other important part is where we grab the Step3 : Randomly Place The 1st 8 Sequentially Obtained Image PortionsNow it wouldn't be much of a puzzle if we laid the squares out in the order
that they were obtained, so we need to shake things up a bit. We need some randomness.
This is achieved by the following method, where we randomly grab the 8 sequentially
obtained unallocated image portions and allocate them to a allocated private void RandomizeTiles()
{
Random rand = new Random();
int allocated = 0;
while (allocated != 8)
{
int index = 0;
if (initialUnallocatedParts.Count > 1)
{
index = (int)(rand.NextDouble() * initialUnallocatedParts.Count);
}
allocatedParts.Add(initialUnallocatedParts[index]);
initialUnallocatedParts.RemoveAt(index);
allocated++;
}
}
We then need to fill the int index = 0;
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
allocatedParts[index].SetValue(Grid.RowProperty, i);
allocatedParts[index].SetValue(Grid.ColumnProperty, j);
gridMain.Children.Add(allocatedParts[index]);
index++;
}
}
Step4 : Allow The User To Click One Of The Image Portion SquaresAs we cunningly used This is done as follows: private void rectPart_MouseDown(object sender, MouseButtonEventArgs e)
{
//get the source Rectangle, and the blank Rectangle
//NOTE : Blank Rectangle never moves, its always the last Rectangle
//in the allocatedParts List, but it gets re-allocated to
//different Gri Row/Column
Rectangle rectCurrent = sender as Rectangle;
Rectangle rectBlank = allocatedParts[allocatedParts.Count - 1];
//get current grid row/col for clicked Rectangle and Blank one
int currentTileRow = (int)rectCurrent.GetValue(Grid.RowProperty);
int currentTileCol = (int)rectCurrent.GetValue(Grid.ColumnProperty);
int currentBlankRow = (int)rectBlank.GetValue(Grid.RowProperty);
int currentBlankCol = (int)rectBlank.GetValue(Grid.ColumnProperty);
//create possible valid move positions
List<PossiblePositions> posibilities = new List<PossiblePositions>();
posibilities.Add(new PossiblePositions
{ Row = currentBlankRow - 1, Col = currentBlankCol });
posibilities.Add(new PossiblePositions
{ Row = currentBlankRow + 1, Col = currentBlankCol });
posibilities.Add(new PossiblePositions
{ Row = currentBlankRow, Col = currentBlankCol-1 });
posibilities.Add(new PossiblePositions
{ Row = currentBlankRow, Col = currentBlankCol + 1 });
//check for valid move
bool validMove = false;
foreach (PossiblePositions position in posibilities)
if (currentTileRow == position.Row && currentTileCol == position.Col)
validMove = true;
//only allow valid move
if (validMove)
{
rectCurrent.SetValue(Grid.RowProperty, currentBlankRow);
rectCurrent.SetValue(Grid.ColumnProperty, currentBlankCol);
rectBlank.SetValue(Grid.RowProperty, currentTileRow);
rectBlank.SetValue(Grid.ColumnProperty, currentTileCol);
}
else
return;
}
And that's it. Really simply, as I said in the intro, but you never know you
may have just learnt a bit about the WPF Anyway why not try your luck. Have a go. Though I must say I have not been able to complete 1 puzzle at all as yet. I never was much good at these damn puzzles. Grrrrr Historyv1.0 25/04/08
|
||||||||||||||||||||||