JavaScript实现十五拼图

css代码

body {
    font-family: cursive;
    font-size: 14pt;
    text-align: center;
}

#puzzlearea {
    height: 400px;
    margin: 0 auto;
    position: relative;
    width: 400px;
}

.highlight {
    border-color: red;
    cursor: pointer;
}

.puzzletile {
    background-image: url("../background.jpg");
    border: 5px solid black;
    position: absolute;
}

.highlight, #output {
    color: red;
}

.puzzletile, #output {
    font-size: 40pt;
}

html代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>CSE 154 Fifteen Puzzle</title>
    <!-- your files that you will write -->
    <link href="css/fifteen.css" type="text/css" rel="stylesheet"/>
    <script src="js/fifteen.js" type="text/javascript"></script>

</head>
<body>
<h1>Fifteen Puzzle</h1>

<p>
    The goal of the fifteen puzzle is to un-jumble its fifteen squares
    by repeatedly making moves that slide squares into the empty space.
    How quickly can you solve it?
</p>

<div id="puzzlearea">
    <!--
       this area holds the actual fifteen puzzle pieces
       add to it as you need to
    -->
</div>

<p id="controls">
    <button id="shufflebutton">Shuffle</button>
</p>

<div id="output"></div>

<p>
    American puzzle author and mathematician Sam Loyd is often falsely
    credited with creating the puzzle; indeed, Loyd claimed from 1891
    until his death in 1911 that he invented it.
    The puzzle was actually created around 1874 by Noyes Palmer Chapman,
    a postmaster in Canastota, New York.
</p>
</body>
</html>

JavaScript代码

(function () {
   "use strict";

   let NUM = 4; //拼图的行列数 the number of rows/cols in the puzzle
   let spaceRow = 3; // 空白图块所在行
   let spaceColumn = 3; // 空白图块所在列
   let WIDTH = 100; // the pixel width/height of each tile

   // gets everything set when the window has loaded
   window.onload = function () {
      setSize();
      document.getElementById("select").onchange = changeSize;
      document.getElementById("shufflebutton").onclick = shuffle;
      createSquares();

   };

   // add a drop-down list to select difficulty level
   // 设置下拉列表 默认选中 option4
   function setSize() {
      var select = document.createElement("select");
      select.id = "select";
      for (var i = 3; i < 7; i++) {
         var option = document.createElement("option");
         option.innerHTML = i + " * " + i;
         option.value = i;
         option.id = "option" + i;
         select.appendChild(option);
      }
      document.getElementById("controls").appendChild(select);
      document.getElementById("option4").selected = "selected";
   }


   function changeSize() {
      NUM = this.value;
      spaceRow = this.value - 1;
      spaceColumn = this.value - 1;
      WIDTH = parseInt(400 / this.value);
      var puzzlearea = document.getElementById("puzzlearea");
      while (puzzlearea.contains(document.querySelector(".puzzletile"))) {
         puzzlearea.removeChild(document.querySelector(".puzzletile"));
      }
      createSquares();
   }

   // creates 15 puzzle tiles and sets them to their initial position
   function createSquares() {
      for (var i = 1; i < NUM * NUM; i++) {
         var div = document.createElement("div");
         div.className = "puzzletile";
         div.innerHTML = i;
         var row = Math.floor((i - 1) / NUM);
         var column = (i - 1) % NUM;
         var x = column * -1 * WIDTH + "px";
         var y = row * -1 * WIDTH + "px";

         // 减去边框的宽度 并且宽高相等
         div.style.height = WIDTH - 10 + "px";
         div.style.width = div.style.height;
         // 设置background 的 position
         div.style.backgroundPosition = x + " " + y;
         // 为每个拼图添加ID
         div.id = "square_" + row + "_" + column;
         // 设置水平和垂直方向的偏移量
         div.style.top = row * WIDTH + "px";
         div.style.left = column * WIDTH + "px";
         setEvents(div);
         document.getElementById("puzzlearea").appendChild(div);
      }
   }

   // shuffles puzzle tiles for 1000 times
   function shuffle() {
      // 实现Shuffle算法
      for (let j = 0; j < 1000; j++) {
         let neigbors = [];
         // 将所有的拼图 存储到 allPuzzles中
         let allPuzzles = document.getElementsByClassName("puzzletile");
         // 将与空白图块相邻的拼图 存储到数组neigbors中
         for (let i = 0; i < allPuzzles.length; i++) {
            // 判断拼图是否可以移动
            if (moveable(allPuzzles[i]))
               neigbors.push(allPuzzles[i]);
            }
         // 得到一个随机的索引
         let ranNum = getRandomIntInclusive(0, neigbors.length - 1);
         // 获取需要移动的拼图移动之前的偏移量
         let tempTop = neigbors[ranNum].style.top;
         let tempLeft = neigbors[ranNum].style.left;
         // 将拼图移动到空白图块处
         neigbors[ranNum].style.top = spaceRow * WIDTH + "px";
         neigbors[ranNum].style.left = spaceColumn * WIDTH + "px";
         neigbors[ranNum].id = "square_" + spaceRow + "_" + spaceColumn;
         // 更改空白图块的位置
         spaceRow = parseInt(tempTop) / WIDTH;
         spaceColumn = parseInt(tempLeft) / WIDTH;
      }


   }

   // 获取指定区间的随机数
   function getRandomIntInclusive(min, max) {
      min = Math.ceil(min);
      max = Math.floor(max);
      return Math.floor(Math.random() * (max - min + 1)) + min;
   }

   // sets up events for all puzzle tiles
   function setEvents(div) {
      div.onmouseover = function () {
         if (moveable(this)) {
            this.classList.add("highlight"); // when mouse over, adds class "highlight"
         }
      };
      div.onmouseout = function () {
         // when mouse out, removes class "highlight"
         if (moveable(this)) {
            this.classList.remove("highlight"); // when mouse out, remove class "highlight"
         }
      };
      div.onclick = helper;
   }

   // a helper function for function "makeAMove"
   // displays "congratulations" if the player wins
   function helper() {
      if (moveable(this)) {
         makeAMove(this);
         if (win()) {
            document.getElementById("output").innerHTML = "Congratulations! You win!";
         } else {
            document.getElementById("output").innerHTML = "";
         }
      }
   }

   // make one move for the given tile
   function makeAMove(div) {

      div.id = "square_" + spaceRow + "_" + spaceColumn;
      var divRow = parseInt(div.style.top) / WIDTH;
      var divColumn = parseInt(div.style.left) / WIDTH;

      div.style.top = spaceRow * WIDTH + "px";
      div.style.left = spaceColumn * WIDTH + "px";
      spaceRow = divRow;
      spaceColumn = divColumn;

   }

   // return true if the given tile is moveable
   function moveable(div) {

      var divRow = parseInt(div.style.top) / WIDTH;
      var divColumn = parseInt(div.style.left) / WIDTH;
      if (spaceRow == divRow) {
         return Math.abs(spaceColumn - divColumn) == 1;
      }
      else if (spaceColumn == divColumn) {
         return Math.abs(spaceRow - divRow) == 1;
      }
      else {
         return false;
      }
   }

   // return true if all tiles are at their original positions
   function win() {
      var tiles = document.querySelectorAll(".puzzletile");
      for (var i = 0; i < tiles.length; i++) {
         var row = Math.floor(i / NUM);
         var column = i % NUM;
         if (tiles[i].id != "square_" + row + "_" + column) {
            console.log(tiles[i].id);
            return false;
         }
      }
      return true;
   }
})();

最后的效果
JavaScript实现十五拼图