jQuery sliding puzzle game

by Chuck Catron | Apr 15, 2013 I have been reading jQuery Hotshot. The first chapter teaches you how to make a sliding puzzle. The first part to making the puzzle is to lay out the html.
<div id="puzzle" class="clearfix"> <figure> <img src="img/leaf.jpg" /> </figure> <div id="ui"> <p id="time">Current time: <span>00:00:00</span> </p> <button id="start">Start!</button> </div> </div>

This is a simple layout and simply puts the puzzle on the screen and ready to go. The jQuery that runs the show is a bit more involved but not too crazy. Our basic variables:
//Basic variables for the puzzle var numberOfPieces = 12, aspect = "3:4", //columns / rows aspectW = parseInt(aspect.split(":")[0]), aspectH = parseInt(aspect.split(":")[1]), container = $("#puzzle"), imgContainer = container.find("figure"), img = imgContainer.find("img"), path = img.attr("src"), piece = $("<div/>"), pieceW = Math.floor(img.width() / aspectW), pieceH = Math.floor(img.height() / aspectH), idCounter = 0, positions = [], empty = { top: 0, left: 0, bottom: pieceH, right: pieceW }, previous = {}, timer, currentTime = {}, timerDisplay = container.find("#time").find("span");

Next we have to break the image up into puzzle pieces. Using the "aspect" variable from above we see that the puzzle needs to be 3 columns by 4 rows. So we use nested for loops that basically read for each row we need we will do 3 loops to make the columns. For each iteration of the inner loop will copy a section of the image and store it off into a new array called "positions". Once all the loops have completed we have an array that is the base image broken up into pieces.

//Remove the first item from the positions array positions. y = aspectH.remove(). a < b. a++) { var top = pieceH * x. } while(--i){ var j = Math. x++) { for(var a = 0.clone() . The method used here is based on the Fisher-Yates shuffle algorithm.random() * (i + 1)). xxx Now you are ready to shuffle the array. "px" ]. tempj = array[j]. left: left}).push({top: top. backgroundPosition: [ "-". idCounter++) .floor(Math. "-". path. array[i] = tempj. position: "absolute". tempi = array[i].appendTo(imgContainer).attr("id".join("") }). var pieces = imgContainer. x < y.css({ width: pieceW. array[j] = tempi. pieceW * a.Here is the code: //Break the image up into pieces for(var x = 0.join(""). top: top. left: left. pieceH * x. ")"]. left = pieceW * a. //Remove the first piece of the puzzle container.shift(). b = aspectW.remove(). backgroundImage: ["url(". if(i === 0){ return false.length. height: pieceH. positions. "px ".find("#0"). piece.children(). } } . } } Next you will need to do some basic cleanup work: //Remove the original image img. function shuffle(array){ var i = array.

return false.draggable("option".helper).top){ ui.helper.top = 0.helper.top === empty. } previous. }).css({ top: previous. ui){ var current = getPosition(ui.left === empty. $. .left. function(i){ pieces.left){ ui.helper. "y"). return false.top || current.top === empty. }.draggable("option".left = 0.top || current.eq(i).appendTo(imgContainer). start: function(e. ui){ var current = getPosition(ui.left > empty. if(current.left }).helper.right || current.bottom || current.trigger("mouseup").draggable({ containment: "parent". } else if(current. pieceH].trigger("mouseup") . } }. previous.top. pieces.right < empty.bottom || current.trigger("mouseup").bottom < empty.top = current. "axis". ui. if(current. return false.left) { ui.top > empty. grid: [pieceW.helper).right < empty.helper.left > empty.top > empty.shuffle(pieces). } if(current. pieces. } if(current.left){ ui.helper.right || current. "revert".trigger("mouseup"). empty.helper.draggable("option". false). drag: function(e.top. return false.each(pieces.left){ ui.top && current. empty. xxx Next using jQuery-UI functions we can make the pieces draggable. left: previous.left === empty.css(positions[i]). "axis".left = current.bottom < empty. } else { ui. "x").

hours * 60 * 60) + (currentTime. function (i) { var currentPiece = $("#" + (i + 1)).top + pieceH. empty.css("left")) + pieceW } } .length) { clearInterval(timer).top === empty.seconds.bottom = previous. right: parseInt(el. $("<p/>". var totalSeconds = (currentTime. } }).top = previous.left) { correctPieces++.appendTo("#ui"). totalSeconds). currentPosition = getPosition(currentPiece). correctPieces = 0.left === empty. empty.minutes * 60) + currentTime.top && current.getItem("puzzleBestTime").css("top")) + pieceH. $("<p/>".css("top")). ui){ var current = getPosition(ui. empty.left = previous. if (correctPieces === positions. { text: "Congratulations. bottom: parseInt(el.getItem("puzzleBestTime")) { var bestTime = localStorage.css("left")). { text: "You got a new best time!" }). if (totalSeconds < bestTime) { localStorage.each(positions.top && positions[i].helper). left: parseInt(el.setItem("puzzleBestTime".appendTo("#ui"). } } else { localStorage.left) { empty. } } } }).left === currentPosition.left + pieceW. function getPosition(el) { return { top: parseInt(el. if (localStorage. } $. if (current. if (positions[i].stop: function(e.right = previous.setItem("puzzleBestTime". $("<p/>".left.top === currentPosition. { text: "You got a new best time!" }). totalSeconds). you solved the puzzle!" }).appendTo("#ui").top.

Sign up to vote on this title
UsefulNot useful