HomeJavascriptSliding Image Puzzle Javascript

Sliding Image Puzzle Javascript

Welcome to yet another exciting tutorial by Coding Artist. Building projects is one of the best ways to learn JavaScript. So in today’s tutorial let us expand our javascript knowledge with a fun and easy-to-build project called ‘Sliding Puzzle Game’. To build this project we need HTML, CSS, and Javascript.

Video Tutorial:

Before we move on to the actual tutorial, you can check out the video tutorial of this post here. If you like video tutorials like this subscribe to my YouTube channel, where I post new projects based on HTML, CSS, and Javascript regularly.

Project Folder Structure:

Let’s build the project folder structure before we begin writing the code. We create a project folder called ‘Sliding Puzzle Game’. Inside this folder, we have three files. These files are index.html, style.css, and script.js. Apart from these, we have images for our puzzle and the original image.

HTML:

We begin with the HTML Code. First, create a file called – ‘index.html’. Copy the code below and paste it into your HTML file.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Sliding Puzzle Game</title>
    <!-- Google Fonts -->
    <link
      href="https://fonts.googleapis.com/css2?family=Poppins&display=swap"
      rel="stylesheet"
    />
    <!-- Stylesheet -->
    <link rel="stylesheet" href="style.css" />
  </head>
  <body>
    <div class="cover-screen">
      <p id="result"></p>
      <button id="start-button">Start Game</button>
    </div>
    <div id="moves"></div>
    <div class="slider-game">
      <div class="container"></div>
      <div class="original-image">
        <img src="original_image.png" alt="" />
      </div>
    </div>
    <!-- Script -->
    <script src="script.js"></script>
  </body>
</html>

CSS:

Next, we style our game using CSS. For this copy, the code provided to you below and paste it into your stylesheet.

* {
  padding: 0;
  margin: 0;
  box-sizing: border-box;
  font-family: "Poppins", sans-serif;
}
img {
  max-width: 100%;
}
.slider-game {
  width: 80%;
  display: flex;
  justify-content: space-between;
  margin: 0 auto;
  margin-top: 5%;
}
.container {
  display: grid;
  width: 25em;
  height: 25em;
  grid-template-columns: repeat(3, 1fr);
  grid-auto-rows: 8em;
}
.original-image {
  width: 25em;
  height: 25em;
}
.image-container {
  border: 1px solid #ffffff;
}
.cover-screen {
  position: absolute;
  top: 0;
  left: 0;
  background-color: #edb506;
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}
#start-button {
  font-size: 1.2em;
  padding: 0.8em 2em;
  border: none;
  border-radius: 3em;
  cursor: pointer;
}
#moves {
  position: relative;
  margin: 1em;
  text-align: right;
}
.hide {
  display: none;
}
@media only screen and (max-width: 768px) {
  .slider-game {
    flex-direction: column;
  }
  .container {
    width: 20em;
    height: 20em;
    grid-auto-rows: 6em;
  }
  .original-image {
    width: 20em;
    height: 20em;
  }
}

Javascript:

Next, we style our game using CSS. For this copy, the code provided to you below and paste it into your stylesheet.

Finally, we add functionality to the game using Javascript. Once again copy the code below and paste it into your script file.

The game involves a grid of 3×3 squares, with each square containing an image. The goal is to slide the image parts around to get them in the correct order, with one blank square to help with the sliding.

The steps involved in making this code are:

  • First, start with variable initializations and references.
  • Then call the ‘randomImages’ function to fill an array with random values for the images.
  • Then call the ‘gridGenerator’ function to generate the game grid based on the randomized image array.
  • When the user clicks on an image the ‘selectImage’ function is called. It checks whether the clicked image is adjacent to the blank image and swaps their positions if they are. It also increments the moves count and checks whether the user has won the game.
  • The start button event listener initializes the game by generating a new grid and resetting the moves count to zero.
  • Finally, create a function so that when the window loads we could display the cover screen.
//Initial References
const moves = document.getElementById("moves");
const container = document.querySelector(".container");
const startButton = document.getElementById("start-button");
const coverScreen = document.querySelector(".cover-screen");
const result = document.getElementById("result");
let currentElement = "";
let movesCount,
  imagesArr = [];
const isTouchDevice = () => {
  try {
    //We try to create TouchEvent (it would fail for desktops ad throw error)
    document.createEvent("TouchEvent");
    return true;
  } catch (e) {
    return false;
  }
};
//Random number for image
const randomNumber = () => Math.floor(Math.random() * 8) + 1;

//Get row and column value from data-position
const getCoords = (element) => {
  const [row, col] = element.getAttribute("data-position").split("_");
  return [parseInt(row), parseInt(col)];
};

//row1, col1 are image co-ordinates while row2 amd col2 are blank image co-ordinates
const checkAdjacent = (row1, row2, col1, col2) => {
  if (row1 == row2) {
    //left/right
    if (col2 == col1 - 1 || col2 == col1 + 1) {
      return true;
    }
  } else if (col1 == col2) {
    //up/down
    if (row2 == row1 - 1 || row2 == row1 + 1) {
      return true;
    }
  }
  return false;
};

//Fill array with random value for images
const randomImages = () => {
  while (imagesArr.length < 8) {
    let randomVal = randomNumber();
    if (!imagesArr.includes(randomVal)) {
      imagesArr.push(randomVal);
    }
  }
  imagesArr.push(9);
};

//Generate Grid
const gridGenerator = () => {
  let count = 0;
  for (let i = 0; i < 3; i++) {
    for (let j = 0; j < 3; j++) {
      let div = document.createElement("div");
      div.setAttribute("data-position", `${i}_${j}`);
      div.addEventListener("click", selectImage);
      div.classList.add("image-container");
      div.innerHTML = `<img src="image_part_00${
        imagesArr[count]
      }.png" class="image ${
        imagesArr[count] == 9 ? "target" : ""
      }" data-index="${imagesArr[count]}"/>`;
      count += 1;
      container.appendChild(div);
    }
  }
};

//Click the image
const selectImage = (e) => {
  e.preventDefault();
  //Set currentElement
  currentElement = e.target;
  //target(blank image)
  let targetElement = document.querySelector(".target");
  let currentParent = currentElement.parentElement;
  let targetParent = targetElement.parentElement;

  //get row and col values for both elements
  const [row1, col1] = getCoords(currentParent);
  const [row2, col2] = getCoords(targetParent);

  if (checkAdjacent(row1, row2, col1, col2)) {
    //Swap
    currentElement.remove();
    targetElement.remove();
    //Get image index(to be used later for manipulating array)
    let currentIndex = parseInt(currentElement.getAttribute("data-index"));
    let targetIndex = parseInt(targetElement.getAttribute("data-index"));
    //Swap Index
    currentElement.setAttribute("data-index", targetIndex);
    targetElement.setAttribute("data-index", currentIndex);
    //Swap Images
    currentParent.appendChild(targetElement);
    targetParent.appendChild(currentElement);
    //Array swaps
    let currentArrIndex = imagesArr.indexOf(currentIndex);
    let targetArrIndex = imagesArr.indexOf(targetIndex);
    [imagesArr[currentArrIndex], imagesArr[targetArrIndex]] = [
      imagesArr[targetArrIndex],
      imagesArr[currentArrIndex],
    ];

    //Win condition
    if (imagesArr.join("") == "123456789") {
      setTimeout(() => {
        //When games ends display the cover screen again
        coverScreen.classList.remove("hide");
        container.classList.add("hide");
        result.innerText = `Total Moves: ${movesCount}`;
        startButton.innerText = "RestartGame";
      }, 1000);
    }
    //Increment a display move
    movesCount += 1;
    moves.innerText = `Moves: ${movesCount}`;
  }
};

//Start button click should display the container
startButton.addEventListener("click", () => {
  container.classList.remove("hide");
  coverScreen.classList.add("hide");
  container.innerHTML = "";
  imagesArr = [];
  randomImages();
  gridGenerator();
  movesCount = 0;
  moves.innerText = `Moves: ${movesCount}`;
});

//Display start screen first
window.onload = () => {
  coverScreen.classList.remove("hide");
  container.classList.add("hide");
};

Go ahead and customize the project the way you like. If you have any queries, suggestions, or feedback comment below. Download the source code by clicking on the ‘Download Code’ button below.

RELATED ARTICLES

1 COMMENT

LEAVE A REPLY

Please enter your comment!
Please enter your name here

four × three =

Most Popular