Click here to Skip to main content
15,867,330 members
Articles / Programming Languages / C#

Full Game of Sliding Puzzle

Rate me:
Please Sign up or sign in to vote.
4.57/5 (18 votes)
24 Dec 2010GPL33 min read 74.8K   11.6K   28   12
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.

C#
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.

C#
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.

C#
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.

C#
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

C#
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.

C#
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.

C#
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)


Written By
Software Developer
Spain Spain
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
Questionneed code thank you Pin
Jonathan Valenzuela20-Dec-19 18:24
Jonathan Valenzuela20-Dec-19 18:24 
Questionneed code thank you Pin
Jonathan Valenzuela20-Dec-19 18:24
Jonathan Valenzuela20-Dec-19 18:24 
Generalmy vote of 5 Pin
Paulo Augusto Kunzel24-Oct-13 3:11
professionalPaulo Augusto Kunzel24-Oct-13 3:11 
GeneralMy vote of 5 Pin
AmitGajjar11-Sep-13 18:13
professionalAmitGajjar11-Sep-13 18:13 
GeneralI have also created the same long back Pin
Anurag Gandhi27-Dec-10 8:35
professionalAnurag Gandhi27-Dec-10 8:35 
GeneralRe: I have also created the same long back Pin
Alberto M.28-Dec-10 0:23
Alberto M.28-Dec-10 0:23 
Generali am going to play this Pin
Pranay Rana26-Dec-10 18:48
professionalPranay Rana26-Dec-10 18:48 
Generalbut i like it.... Pin
Rozis25-Dec-10 5:14
Rozis25-Dec-10 5:14 
GeneralHave more. Pin
Hiren solanki24-Dec-10 16:38
Hiren solanki24-Dec-10 16:38 
It looks like just you're advertising your product or you are explaining non-devloper By just showing different Images of your project.

Remove unnecessary images and add some more content.

Look at THIS[^] article content you will get an idea. Smile | :)

Nice try, Keep it up.
Regards,
Hiren.
My Recent Article: - Way to know which control have raised a postback
My Recent Tip/Trick: - The ?? Operator.

GeneralRe: Have more. Pin
Alberto M.24-Dec-10 22:31
Alberto M.24-Dec-10 22:31 
GeneralNeeds More Content Pin
#realJSOP24-Dec-10 10:08
mve#realJSOP24-Dec-10 10:08 
GeneralLinks error - fixed Pin
Alberto M.24-Dec-10 6:31
Alberto M.24-Dec-10 6:31 

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

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