Search code examples
javascripthtmlcsspuzzle

Sliding puzzle for javascript


I want to create a sliding puzzle with different formats like: 3x3, 3x4, 4x3 and 4x4. When you run my code you can see on the right side a selection box where you can choose the 4 formats.

I can move each puzzlepiece to blank space but the problem is that it shouldn't be possible to shift pieces diagonal aswell as only pieces which directly border on the blank space not from further away. Anyone knows how to fix that? Here is an good example how the puzzle should work: http://www.yash.info/jspuzzle.htm

In the javascript code you can see the first function load() is to replace every piece with the blank one and the functions after that are to select a format and change the format into it. The function Shiftpuzzlepieces makes it so that you can move each piece into the blank space. If you have any more question or understanding issues just feel free to ask in the comments. Many thanks in advance.

Since I don't have enough reputation I will post a link to the images here: https://i.sstatic.net/9fIyk.jpg . These images are just placeholders right now.

//jscript:

  function load() {
  var puzzle = '<div id="slidingpuzzleContainer4x4">';

  for (var i = 0; i <= 15; ++i) {
    puzzle += '<img src="images/blank.jpg" alt="blank" width="100" height="100" />';
  }
  puzzle += '</div>';
  showSlidingpuzzle(puzzle);
}


function changeFormat(x, y) {
  var puzzlepieces = [];
  var finalValue = x * y - 2;

  for (var i = 0; i <= finalValue; ++i) {
    puzzlepieces.push(i);
  }

  puzzlepieces.push('blank')
  createSlidingpuzzle(puzzlepieces, x, y);
}


function createSlidingpuzzle(puzzlepieces, x, y) {

  var puzzle = '<div id="slidingpuzzleContainer' + x + 'x' + y + '">';

  for (var puzzleNr = 0; puzzleNr < puzzlepieces.length; ++puzzleNr) {
    puzzle += '<img src="images/' + puzzlepieces[puzzleNr] + '.jpg" class="puzzlepiece" id="position' + puzzlepieces[puzzleNr] + '" alt="' + puzzlepieces[puzzleNr] + '" onclick="shiftPuzzlepieces(this);" width="100" height="100" />';
  }
  puzzle += '</div>';

  showSlidingpuzzle(puzzle);
}


function showSlidingpuzzle(puzzle) {
  document.getElementById('slidingpuzzleContainer').innerHTML = puzzle;
}


function shiftPuzzlepieces(el) {

var blank = document.getElementById("positionblank"); 
var temp = el.parentNode.insertBefore(document.createElement('a'), el); 
el.parentNode.insertBefore(el, blank); 
el.parentNode.insertBefore(blank, temp); 
el.parentNode.removeChild(temp); 

}
/**css:**/

body {
  font-family: "Lucida Grande", "Lucida Sans Unicode", Verdana, Helvetica, Arial, sans-serif;
  font-size: 12px;
  color: #000;
}

img {
  padding: 0;;
  margin: 0;
}

#slidingpuzzleContainer3x3,
#slidingpuzzleContainer3x4,
#slidingpuzzleContainer4x3,
#slidingpuzzleContainer4x4 {
  position: absolute;
  top: 50px;
  left: 50px;
  border: 1px solid black;
}

#slidingpuzzleContainer3x3 {
  width: 300px;
  height: 300px;
}

#slidingpuzzleContainer3x4 {
  width: 300px;
  height: 400px;
}

#slidingpuzzleContainer4x3 {
  width: 400px;
  height: 300px;
}

#slidingpuzzleContainer4x4 {
  width: 400px;
  height: 400px;
}

.puzzlepiece {
  float: left;
}

#formatContainer {
  position: absolute;
  top: 50px;
  left: 500px;
}

#format {
  margin-top: 10px;
}
<!--HTML-->
<body onload="load();">

  <div id="slidingpuzzleContainer">
  </div>

  <div id="formatContainer">
    select format:<br />
 <select name="format" id="format" size="1" onChange="this.options[this.selectedIndex].onclick()">
            <option onclick="changeFormat(3,3);">Format 3 x 3</option>
            <option onclick="changeFormat(3,4);">Format 3 x 4</option>
            <option onclick="changeFormat(4,3);">Format 4 x 3</option>
            <option onclick="changeFormat(4,4);">Format 4 x 4</option>
        </select>

  </div>


</body>


Solution

  • In shiftPuzzlePieces(el) function, you should first check if el is adjacent to blank piece. If so, then shift it. Here is the jsFiddle

    function shiftPuzzlepieces(el) {
    var elIndex=0;
    var child=el;
    while((child=child.previousSibling)!=null) elIndex++;    
    //position of el is stored in elIndex
    
    var blankIndex=0;
    var blank = document.getElementById("positionblank");
    child=blank;
    while((child=child.previousSibling)!=null) blankIndex++;
    //position of blank is stored in blankIndex
    
    //Now the number of columns is needed to compare between positions of el and blank. 
    //I have stored this in global variable cols
    
    //Now check if el and blank are adjacent
    if((((elIndex==blankIndex-1) || (elIndex==blankIndex+1) )
       && ((Math.floor(elIndex/cols))==(Math.floor(blankIndex/cols)))
       ) || (elIndex==blankIndex+cols) || (elIndex==blankIndex-cols) ){
     var temp = el.parentNode.insertBefore(document.createElement('a'), el);
    el.parentNode.insertBefore(el, blank);
    el.parentNode.insertBefore(blank, temp);
    el.parentNode.removeChild(temp);
    }
    }