Click here to Skip to main content
Click here to Skip to main content

Full Game of Sliding Puzzle

, 24 Dec 2010
Rate this:
Please Sign up or sign in to vote.
This is a full game version of sliding puzzle

Introduction

img1.png

I want to present my first project that I make in the first stage of the 2º course. It's a classic sliding puzzle, but I included more features. You can preview the solution, pause the game, view the shuffle effect, 2 skins, 3 board sizes (3x3, 4x4 and 5x5), so on...

Important Note

All of the code has comments, but in Spanish. You can translate this using the Google translator.
The reason is that it's a school project.

Quick View of Game Features

  1. Shuffle effect: You can see how the cards are shuffled.
  2. Preview the solution: You can see a preview of the solution, and while you're watching, the game is paused. (The preview of the solution is shown in grayscale).
  3. Classifications: The game has a database that stores everything related to games results. I decided to save in a database because this way I can do searches and filtering in an easier way. For example, while playing with a 3x3 board, you will not see the ratings board 4x4 and 5x5, and only compete in your category. The position on the classification is determined by elapsed time and then by the movements.
  4. Skins: The game has two skins, zen and aluminum. The Zen theme is a style of wood, while the aluminum is a metal style.
  5. Pause: You can pause the game whenever you want, and resume the game later.
  6. Board Size: The game has 3 board sizes (3x3, 4x4, 5x5).
  7. Insert images on the board: You can insert your own pictures on the board. Sliding Puzzle cuts it in the appropriate size and inserted. The game is ready for any size image if the image is smaller than the board, will stretch the image, and if it is larger, shrink the image.
    Note: To give more playability, you can number the images or not.
  8. Arrows in real time: You can see the possible directions you can take in real time, using the blue arrows.

Game Screenshots

img1.png

Zen Theme

img3.png

Aluminium Theme

img2.png

Classifications Form

img5.png

Game with images and numered images

img6.png

While you are previewing the solution

img4.png

Main menu

Using my Class clsImage to Crop the Image

How you can cut an image using my class clsImage?

To crop an image using my clsImage class is very easy, just set the image path in the property "Establecer_Ruta", then call the function "Preparar_Imagen" and arguments we pass the size of the board, and the desired size each piece of the picture. To retrieve each piece, simply call the function "GetImageFromIndex" and as a parameter index in the list.

Sample

This example cuts an image into 9 pieces and returns the first piece. Each piece has a size of 70x70.

private Image CropImage(string imagePath)
{
    clsImage imageClass = new clsImage();
    imageClass.Establecer_Ruta = imagePath;
    imageClass.Preparar_Imagen(3,3,70,70);
    return imageClass.GetImageFromIndex(0);
}

Some Enumerations and Structures

Enumeration "enumDirection"

This enumeration contains the possible directions that can have a tab. This list is used to create a list of possible addresses that can take a tab.

public enum enumDireccion
{
    Arriba = 0,     //Up
    Abajo = 1,      //Down
    Izquierda = 2,  //Left
    Derecha = 3     //Right
}

Structure "structFicha"

This structure is stored in the property "tag" of each board PictureBox, and contains the current position of the chip on the board, the position should be, and a Boolean value that indicates whether the card is empty or not.

private struct structFicha
{
    public int Posicion;  //Contains the current position of the tab within the board.
    public int Valor;     //Contains the final position that should occupy 
			//the tab within the board.
    public bool Comodin;  //Indicates whether the tab, is empty or not. Tab (wildcard)
}

Enumeration "enumGameStatus"

This enumeration contains all possible states in which the game can be.

private enum enumGameStatus
{ 
    Iniciada = 0,   //This state indicates that the game is started.
    Pausada = 1,    //This state indicates that the game is paused.
    Finalizada = 2, //This state indicates that the game is finished or is resolved. 
    Scramble = 3,   //This status indicates that the game is being played out.
}

Scramble Function

private void Scramble()
{
    .....
    while (moves < 100)
    { 
        //Detect the possible moves you can make the empty file, 
        //and store it in a list of the type enumDireccion
        PosiblesDirecciones = Movimientos_Posibles(tmpComodin);
        //CurrentDirection variable contains a possible direction, 
        //obtained with a random from 0 to the maximum addresses obtained
        CurrentDirection = PosiblesDirecciones[rndDirection.Next
			(0, PosiblesDirecciones.Count)];
        //If the variable firstMove equals true, then initialize the 
        //variable lastPosition and the variable firstMove is now false.
        /*
         *for servidng lastPosition?
         *this variable to store the address of which comes from the ad 
         *in its last movement, this tab prevents the rebound. 
         *For example, if the chip has the potential for up / down / left 
         *and left randomly chosen, the following random movement,
         *you can not choose right, because it would cause a rebound.
        */       
        if (firstMove != true)
        {
            if (LastPosition.Equals(CurrentDirection) == false)
            {
                LastPosition = this.DireccionContraria(CurrentDirection);
                Application.DoEvents();
                this.MoverCelda(CurrentDirection, true);
                moves++;
            }
        }
        else
        {
            firstMove = false;
            LastPosition = this.DireccionContraria(CurrentDirection);
            this.MoverCelda(CurrentDirection, true);
            moves++;
        }
    }
}

Function "MoverCelda"

This function is the main game, which is responsible for moving the different tabs on the board. This function receives two parameters, the address to which you want to move the wildcard, and whether or not to move with effect.

private void MoverCelda(enumDireccion Direccion, bool WithEfect)
{
    if ((this.PanelJuego.Controls.Count > 0) && 
	((this.EstadoPartida == enumGameStatus.Iniciada) || 
	(this.EstadoPartida == enumGameStatus.Scramble)) && (this.moveInAction == false))
    {
        //This flag variable is used to determine whether you are moving a tab or not.
        //If flag is removed, can occur if double-click one button direction, 
        //moves two cards simultaneously, this is for threads.
        this.moveInAction = true;
        PictureBox tmpImagen = null;
        Point tmpPoint = new Point();
        //This variable determines whether the motion was valid or not, 
        //if it isn't valid, does not add up as a movement on the board.
        bool movimientoValido = false;
        bool FinPartida = false;
        PictureBox tmpComodin = GetPictureComodin(); //Get the pictureBox wildcard
        switch (Direccion)
        {
            case enumDireccion.Abajo:
                if (tmpComodin.Top != 0)
                {
                    //Hide the pictureBox wildcard for the current arrows are not visible.
                    tmpComodin.Visible = false;
                    tmpImagen = this.GetPictureFromPoints(new Point
		  (tmpComodin.Location.X, tmpComodin.Location.Y - tmpComodin.Height));
                    tmpPoint = new Point(tmpImagen.Location.X, tmpImagen.Location.Y);
                    //Determines whether you move the piece to the effect of moving or not.
                    if (WithEfect == true)
                    {
                        int posY = tmpImagen.Location.Y;
                        for (int i = posY; i <= tmpComodin.Location.Y; i++)
                        {
                            tmpImagen.Location = new Point(tmpComodin.Location.X, i);
                        }
                    }
                    else 
                    { 
                        tmpImagen.Location = new Point
			(tmpComodin.Location.X, tmpComodin.Location.Y);
                    }
                    tmpComodin.Location = new Point(tmpPoint.X, tmpPoint.Y);
                    this.TooglePicturePosition(ref tmpImagen, ref tmpComodin);
                    movimientoValido = true;
                    tmpComodin.Visible = true;
                }
                break;
                            ..........
            }
            //Determine whether the movement has been by the user, 
            //or the shuffle function.
            //We recall that the state of the game when shuffles 
            //the tabs is "enumGameStatus.Scramble" and not "enumGameStatus.Iniciada"
            if (this.EstadoPartida == enumGameStatus.Iniciada)
            {
                //If the movement was a valid move
                if (movimientoValido == true)
                {
                    //Increase the movements on board.
                    this.MovimientosPartida += 1;
                    //Shown the new value of movements maked in the label
                    this.lblStepsValue.Text = Convert.ToString(this.MovimientosPartida);
                    //Evaluated only when "end of game" when the wildcard is 
                    //in the bottom-right position.
                    //This makes optimizing the game, so do not evaluate to play with 
                    //each movement.
                    if (((structFicha)tmpComodin.Tag).Posicion == 
					((structFicha)tmpComodin.Tag).Valor)
                    {
                        FinPartida = this.EvaluarFinJuego();
                    }
                    if (FinPartida != true)
                    {
                        //If isn't the "end of game", we insert the arrows into wildcard
                        tmpComodin.Image = this.Imagen.InsertarArrows
			(this.Theme.imgEmpty, this.Movimientos_Posibles(tmpComodin));
                    }
                }
            }
            this.moveInAction = false;
        }
    }
}

Insert the Arrows into the Blank Images

To insert the arrows on any image, in our case a wildcard image, simply call the function "InsertarArrows" clsImage class. This function receives two parameters, the image that you want to insert arrows, and different arrows to be entered.

public Image InsertarArrows(Image Imagen, List<enumDireccion> Arrows)
{
    Graphics g = null;
    Image tmpImg = null;
    //make a copy of the image to not work with original
    tmpImg = (Image)(Imagen.Clone());
    //create a new variable graphics and say they will work on the copy 
    //of the picture we created
    g = Graphics.FromImage(tmpImg);
    //Create a loop to insert in the image all the arrows that have in the list "Arrows"
    foreach (enumDireccion Arrow in Arrows)
    {
        switch (Arrow)
        {
            case enumDireccion.Arriba:
                //Draw the arrow "UP"
                g.DrawImage(Properties.Resources.arrow_up, new Point
		(30, Imagen.Height - Properties.Resources.arrow_down.Height));
                break;
            case enumDireccion.Abajo:
                //Draw the arrow "DOWN"
                g.DrawImage(Properties.Resources.arrow_down, new Point(30, 0));
                break;
            case enumDireccion.Izquierda:
                //Draw the arrow "LEFT"
                g.DrawImage(Properties.Resources.arrow_left, 
		new Point(Imagen.Width - Properties.Resources.arrow_down.Width, 30));
                break;
            case enumDireccion.Derecha:
                //Draw the arrow "RIGHT"
                g.DrawImage(Properties.Resources.arrow_right, new Point(0, 30));
                break;
         }
     }
     g.Dispose();
     //Freed the resources of variable graphics
     return tmpImg;
}

Resources

The board pictures are included, and also the *. psd (Photoshop). The menu images are the property of http://p.yusukekamiyamane.com/.

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)

About the Author

Alberto Molero
Software Developer
Spain Spain
No Biography provided

Comments and Discussions

 
Generalmy vote of 5 PinprofessionalPaulo Augusto Künzel24-Oct-13 3:11 
GeneralMy vote of 5 Pinprofessional@AmitGajjar11-Sep-13 18:13 
GeneralI have also created the same long back PinmemberAnurag Gandhi27-Dec-10 8:35 
GeneralRe: I have also created the same long back PinmemberAlberto Molero28-Dec-10 0:23 
Generali am going to play this PinmemberPranay Rana26-Dec-10 18:48 
Generalbut i like it.... PinmemberRozis25-Dec-10 5:14 
GeneralHave more. PinmemberHiren Solanki24-Dec-10 16:38 
GeneralRe: Have more. PinmemberAlberto Molero24-Dec-10 22:31 
GeneralNeeds More Content PinmemberJohn Simmons / outlaw programmer24-Dec-10 10:08 
GeneralLinks error - fixed PinmemberAlberto Molero24-Dec-10 6:31 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.140721.1 | Last Updated 25 Dec 2010
Article Copyright 2010 by Alberto Molero
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid