
Making the puzzle functional
Before writing any JavaScript code to create a functional puzzle, let's write down the features of our puzzle and see how we will achieve them.
When the page loads, an image will be displayed to the user in puzzleContainer
, and a Start button will be displayed under it. The image will actually be a collection of 16 different div elements, each having the same background image but a different background position. Using the background-position
CSS property, we will be able to display the complete image to the user. Once the Start button is clicked, we will take these 16 images and place them at random positions inside pieceBox. We will also display a 4 x 4 grid, puzzleContainer
, where any of the 16 pieces could be dropped. We will then attach appropriate event handlers that will allow us to drag an individual puzzle piece from pieceBox
to puzzleContainer
. Once a piece has been moved to puzzleContainer
, it cannot be dropped back to pieceBox
. It can, however, be dragged into any other cell in puzzleContainer
. Once the user has arranged all the pieces, a relevant message will be displayed.
Enough with the theory for now! Let's dive into some practical JavaScript. In your text editor, open the puzzle.js
file.
Creating slices of the image
Write the following code in the puzzle.js
file:
var rows = 4; var cols = 4; $(document).ready(function(){ var sliceStr = createSlices(true); $('#puzzleContainer').html(sliceStr); }); function createSlices(useImage){ var str = ''; var sliceArr = []; for(var i=0, top=0, c=0; i < rows; i++, top-=100) { for(var j=0, left=0; j<cols; j++, left-= 100, c++) { if(useImage) { sliceArr.push('<div style="background-position: ' + left + 'px ' + top +'px;" class="img" data-sequence="'+c+'">'); } else { sliceArr.push('<div style="background-image:none;" class="img imgDroppable">'); } sliceArr.push('</div>'); } } return sliceArr.join(''); }
The 16 div elements will be in the form of a grid of 4 rows and 4 columns. In the preceding code, we defined two variables, rows
and cols
, and set their value to 4
.
Next, there is the $(document).ready(function()
handler, in which we will write our code. Inside this handler, we call the createSlices
function. This function will create the required 16 div elements and return a string with their HTML structure. This string will then be inserted into the puzzleContainer
div element.
After you have written this code, save the puzzle.js
file and refresh the index.html
page on your browser. You will see a screen resembling the following screenshot:

Now let's look at the createSlices
function in detail.
We defined a variable named str
to store the HTML structure. Next, there are two for
loops. In the outer loop, we initialized another variable named top
to 0
, which will be decremented by 100
in each iteration.
Similarly, inside the inner loop, another variable named left
is defined, and this will also be decreased by 100
in each iteration. Inside the inner loop, a div
element is created, where we set the div's left
and top
values using the background-position
CSS property. This is done in order to create all 16 slides with appropriate images.
A CSS class named img
is also added to the div
element. We have already defined CSS properties for this class in the index.html
file. This class sets the background image as kitty.jpg
for the div
element. It also defines the height
and width
of the div
as 100 px
each, and a border
of 1 px
is also applied.
A data attribute named data-sequence
is also added to each div. This attribute will be used later to check whether all the div elements are arranged correctly or not. Its value will be 0
for the first div, 1
for the second div, 2
for the third div, and so on until 15
, which is set as a value for the last div. Once both the loops are completed, we return the complete DOM structure from the function. This structure will now be inserted in div
puzzleContainer
.
To create a complete image using different pieces, we will need perfect placement of the background-image
property. The background-position
property defines the starting left
and top
positions of the background image for that specific div element. Therefore, if we define the background position as background-position: 0px 0px
, it means that the image will get positioned at the top-left corner of element. Similarly, if we set background-position: -100px 0px
, the left corner will skip the initial 100 pixels of the image.
To understand this more clearly, go to the browser page and inspect the DOM using Firebug (you can download this for Firefox from https://addons.mozilla.org/en-US/firefox/addon/firebug/) or Chrome DevTools (check out the help on Google Chrome DevTools at https://developer.chrome.com/devtools). You will see that the DOM structure resembles the following screenshot:

This structure clearly shows 16 different divs, each having a different background-position setting. You can play with these values in Firebug or Chrome Developer tools in the options provided by the browser by increasing or decreasing their values to see how the background images are positioned on a puzzle piece.
Starting the game
Now that we have our puzzle pieces ready, we need to implement the Start button by adding an event handler for it. This event handler will shuffle all the slices created earlier and will place them at random positions in the div, having pieceBox
as the id
. The following code needs to be added to the $(document).ready(function()
handler:
$('#start').on('click', function() { var divs = $('#puzzleContainer > div'); var allDivs = shuffle(divs); $('#pieceBox').empty(); allDivs.each(function(){ var leftDistance = Math.floor((Math.random()*280)) + 'px'; var topDistance = Math.floor((Math.random()*280)) + 'px'; $(this) .addClass('imgDraggable') .css({ position : 'absolute', left : leftDistance, top : topDistance }); $('#pieceBox').append($(this)); }); var sliceStr = createSlices(false); $('#puzzleContainer').html(sliceStr); $(this).hide(); $('#reset').show(); });
Also, outside the $(document).ready(function()
handler, define the shuffle
function. This is the same function that we used in Chapter 1, Designing a Simple Quiz Application:
function shuffle(o) { for(var j, x, i = o.length; i; j = Math.floor(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x); return o; }
We registered a click event handler to the list item with the start
ID. In the first line, we find all the div
elements inside puzzleContainer
in a divs
variable. We pass this array to the shuffle
function in the next line, which randomizes this array and returns it in a variable named allDivs
. Now the allDivs
variable is an array of puzzle pieces (div
elements) in a random order. We need to place these pieces in the piecebox
div.
Since we want these pieces to look scattered inside the pieceBox
div, first we loop over the elements of the allDivs
array. In each loop iteration, we generate two random numbers for the left and top positions for each div. We then set the div's position to absolute and add the left and top values. Since the pieceBox
div has its position set to relative, each of these divs will be positioned using the left and top values relative to pieceBox
. A css
class, imgDraggable
, is also added to each div. This class name will be used while dragging and dropping pieces. Finally, the div is appended to pieceBox
.
The next line uses the createSlices
function again to create a DOM with empty divs and without any background image. The DOM created using this function will be inserted to the puzzleContainer
div again. Note that false
is passed as a parameter to the createSlices
function this time. This is because we do not want any background image in puzzleContainer
when the game starts. This will require some modification in the createSlices
function.
Modify the createSlices
function written earlier to match the following code:
function createSlices(useImage) { var str = ''; for(var i=0, top=0, c=0; i < rows; i++, top-=100) { for(var j=0, left=0; j<cols; j++, left-= 100, c++) { if(useImage) { str+= '<div style="background-position: ' + left + 'px ' + top +'px;" class="img" data-sequence="'+c+'">'; } else { str+= '<div style="background-image:none;" class="img imgDroppable">'; } str+= '</div>'; } } return str; }
If the useImage
argument for the createSlices
function is set to true
, the background image will be used. If it is false
, no background image will be set but a class named imgDroppable
will be added. This class will be used to attach event handlers to the places where the puzzle pieces will be dropped.
Finally, after preparing the DOM for the pieceBox
and puzzleContainer
divs, the Start button is hidden and the Reset button is displayed.
Reload the HTML page in your browser and you should see something resembling the following screenshot:

Reloading the page and clicking the Start button will display different positions of the puzzle pieces every time.
Handling events for puzzle pieces
To be able to move pieces and use the possible movements, we first need to add events. We will have to add two event handlers, one to make the puzzle pieces inside pieceBox
draggable and second to make the puzzleContainer
pieces droppable.
Inside the event handler of the Start button, add a new function call named addPuzzleEvents()
.
Outside the $(document).ready(function())
event handler, define the addPuzzleEvents
function by writing the following code:
function addPuzzleEvents() { $('.imgDraggable').draggable( { revert : 'invalid', start : function(event, ui ){ var $this = $(this); if($this.hasClass('pieceDropped')) { $this.removeClass('pieceDropped'); ($this.parent()).removeClass('piecePresent'); } } }); $('.imgDroppable').droppable({ hoverClass: "ui-state-highlight", accept : function(draggable) { return !$(this).hasClass('piecePresent'); }, drop: function(event, ui) { var draggable = ui.draggable; var droppedOn = $(this); droppedOn.addClass('piecePresent'); $(draggable).detach().addClass('pieceDropped').css({ top: 0, left: 0, position:'relative' }).appendTo(droppedOn); checkIfPuzzleComplete(); } }); }
There are two important points to be remembered here. Whenever a draggable puzzle piece is dropped on a droppable space, a CSS class named pieceDropped
will be added to that draggable piece , which will indicate that the puzzle piece has been dropped. Another CSS class, piecePresent
, will be added to the droppable space on which the piece is dropped. The presence of the piecePresent
CSS class on a space will indicate that the space already has a piece dropped on it and we will disallow dropping any other draggable pieces on it.
All the puzzle pieces in pieceBox
have a CSS class, imgDraggable
, applied to them. We initialized the draggable component for all such pieces. While initializing, we provided two options for the draggable component. The first option is revert
, which we set to invalid
. As you may recall from Chapter 1, Designing a Simple Quiz Application, invalid
means that a draggable piece will revert to its original position if it has not been dropped on any space. This also means when a piece is dropped inside puzzleContainer, you will not be able to place it back inside pieceBox.
Secondly, we added a start
event handler to the piece. This event handler is called when the dragging begins. In the preceding code, we check whether the element being dragged has the pieceDropped
class applied to it. If the pieceDropped
class is not present on it, it means the piece is still inside pieceBox
and has not been dropped in puzzleContainer
yet.
If the pieceDropped
class has been applied to the element, it means the puzzle piece was already dropped and it is being dragged inside puzzleContainer
only. In this case, we want to allow the puzzle piece to be dropped onto other droppables spaces present inside puzzleContainer
. Therefore, we remove the pieceDropped
class from the draggable piece. In the next line, we also remove the piecePresent
class from its parent droppable because we want the parent droppable to accept other draggable items.
Next, we will prepare the droppable space. In puzzleContainer
, we have 16 different divs, which are used to accept the puzzle pieces. All of these have the imgDroppable
CSS class applied to them. We initialize the droppable component using for all elements that have the imgDroppable
class. While initializing, we provide three options, which are as follows:
hoverClass
: In this option, we can specify the name of any CSS class, and it will be applied to the droppable element when a draggable element will be over it. Note that the class name will only be applied when an accepted draggable element is over the droppable element. In the preceding code, we used theui-state-highlight
class, which is available by default in jQueryUI themes.accept
: This option specifies which draggable elements can be dropped on to a droppable space. Either a jQuery selector or a function can be provided. We are using a function here to check whether the current droppable space already has a draggable element dropped in it or not. If the current droppable already has thepiecePresent
class, we returnfalse
, which means that the draggable element will not be allowed to drop on the current droppable space.drop
: This event takes place once an accepted draggable element (described in the previous bullet point) is dropped onto a droppable space. Once the draggable is dropped, we add thepiecePresent
CSS class to the droppable. We also want the dragged puzzle piece to fit to the parent droppable completely. For this, we remove the draggable element from the DOM using jQuery's detach method. Then we add a CSS class,pieceDropped
, to this droppable space. We set itsleft
andtop
positions to0
andposition
torelative
. Finally, we append it to the parent droppable. The CSS properties specified with it fit it to its parent droppable.
After each drop, we call the checkIfPuzzleComplete
function to check whether the puzzle has been solved.
Checking for puzzle completion
Every time a piece is dropped inside puzzleContainer
, we will have to check whether all the pieces are in the correct order or not. To do this, we will create a function named checkIfPuzzleComplete
. This function will be called from the drop event of the droppables. Define this function as shown in the following code:
function checkIfPuzzleComplete() { if($('#puzzleContainer div.pieceDropped').length != 16) { return false; } for(var i = 0; i < 16; i++) { var puzzlePiece = $('#puzzleContainer div.pieceDropped:eq('+i+')'); var sequence = parseInt(puzzlePiece.data('sequence'), 10); if(i != sequence) { $('#message').text('Nope! You made the kitty sad :(').show(); return false; } } $('#message').text('YaY! Kitty is happy now :)').show(); return true; }
It doesn't make any sense to check the puzzle if all 16 pieces have not been placed inside puzzleContainer
. Since each puzzle piece dropped inside puzzleContainer
will have a pieceDropped
CSS class, we find out how many div elements with pieceDropped
classes are present. If they are less than 16, we can assume that all pieces have not been placed inside the puzzle and return false
from the function. If all 16 pieces are present inside puzzleContainer
, we proceed to next step.
You may remember that we assigned a data-sequence
attribute to each puzzle piece. In a correctly solved puzzle, all div elements will be in a sequence, which means their data-sequence
attributes will have values from 0 to 15 in ascending order. Similarly, in an incorrectly solved puzzle, the data-sequence
attributes of all div
elements will still have values from 0 to 15, but they will not be in order.
The for
loop checks the mentioned condition. We are running a loop from 0
to 15
. Each iteration of the loop picks a div
element from puzzleContainer
whose index is equal to current loop value. The eq
jQuery function is used for this purpose. The sequence value for this div
element is then retrieved and compared to the current loop value. If any of the values inside loop does not match this value, it will mean that the puzzle pieces are not in a sequence. In this case, we display the Nope! You made the kitty sad :( message inside the div
with the message
ID, and exit from the function.
If the loop completes all iterations, it means that all puzzle pieces are in order. Then we display the YaY! Kitty is happy now :) message and return from the function. A correctly solved puzzle will resemble the following screenshot:

Resetting the puzzle
To reset the puzzle, all we need to do is create the pieces again and fill puzzleContainer with them. Write the following code inside the $(document).ready(function())
handler to handle the reset button events:
$('#reset').on('click', function() { var sliceStr = createSlices(true); $('#puzzleContainer').html(sliceStr); $('#pieceBox').empty(); $('#message').empty().hide(); $(this).hide(); $('#start').show(); });
In the preceding code, we used the createSlices
function with the true
parameter and inserted the generated HTML inside puzzleContainer
. Next, we emptied the pieceBox
. The success or error message displayed earlier is also hidden. Finally, the Reset button is hidden and the Start button is displayed again.