实现算法:
1. JavaScript动态生成拼图:通过生成16个div,且除最后一个div不使用背景图片以外,其他div都设置拼图图片为背景。然后通过调整background-position来实现效果图中的拼图效果;
2. 打乱拼图:定义一个大小为15的数组,且其中的值依次为1-15,然后通过定义一个比较函数,利用sort(cmp)实现随机打乱,也就生成了一个随机数组,然后根据这个数组改变类名,定义拼图分块的位置;


function cmp() {
    return 0.5-Math.random();
    }


但是,生成的拼图不一定能恢复到原来的样子,必须进行验证,如果没有通过验证,则需要重新生成随机数组,对于这个验证,可以详见这篇博文: 15迷问题的证明(15 puzzle)
3 .非常重要:id用来代表图片的特定位置,如第一行第一个,第二行第三个等,然后通过类来定义left与top属性,即可以通过改变类名来实现元素的移动。
4. 元素的移动:需要判断点击的方格是否与空方格相邻,可以通过offsetTop与offsetLeft属性进行比较判断,然后通过交换被点击方格与空白方格的类名来实现;
5. 检查是否结束游戏:生成拼图时,id与position是一一对应的,因此只需要判断所有元素是否都一一对应,如果都一一对应,游戏结束,否则,继续。

代码如下:

HTML:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Fifteen_puzzle</title>
    <link rel="stylesheet" type="text/css" href="CSS/puzzle.css">
    <script type="text/javascript" src="JS/puzzle.js"></script>
</head>
<body>
    <h1> 拼图游戏 </h1>
    <div id="result"></div>
    <div id="picture"></div>
    <div id="restart">重新开始</div>
    <div id="change_image">更换图片</div>
</body>
</html>


CSS:/* 大布局定位 */
html, body {
    width: 100%;
    height: 100%;
    margin: 0px;
    padding: 0px;
    overflow: hidden;
}/* 元素居中 */
body {
    text-align: center;
}/* 结果显示 */
#result {
    width: 200px;
    height: 50px;
    font-size: 40px;
    color: red;
    font-family: Courier, "Andale Mono", Arial, sans-serif;
}#picture, #restart, #result, #change_image {
    margin-top: 30px;
    margin-left: auto;
    margin-right: auto; 
}/* 拼图容器 */
#picture {
    position: relative;
    width: 350px;
    height: 355px;
    margin-bottom: 30px;
}/* 重新开始按钮 */
#restart, #change_image {
    cursor: pointer;
    width: 120px;
    height: 40px;
    line-height: 40px;
    background-color: #4286F5;
    box-shadow: 3px 4px 15px black;
    color: white;
    font-size: 18px;
    opacity: 0.7;
}#restart:hover, #change_image:hover {
    opacity: 1;
    transform: scale(1.1);
}/* 图片分块 */
.picture_part0 {
    background: url("../Image/1.jpg") no-repeat;
}.picture_part1 {
    background: url("../Image/2.jpg") no-repeat;
}.picture_part0, .picture_part1 {
    transition-duration: 0.2s;
    position: absolute;
    border: solid 1px #969696;
    display: inline-block;
    width: 83px;
    height: 83px;
    margin-bottom: -4px;
    opacity: 0.9;
}.picture_part:hover {
    opacity: 1;
    transform: scale(1.05);
}/* 类名 position_x 代表了位置 */
.position_1, .position_2, .position_3, .position_4 {
    top: 0px;
}.position_5, .position_6, .position_7, .position_8 {
    top: 85px;
}.position_9, .position_10, .position_11, .position_12 {
    top: 170px;
}.position_13, .position_14, .position_15, .position_16 {
    top: 255px;
}.position_1, .position_5, .position_9, .position_13 {
    left: 0px;
}.position_2, .position_6, .position_10, .position_14 {
    left: 85px;
}.position_3, .position_7, .position_11, .position_15 {
    left: 170px;
}.position_4, .position_8, .position_12, .position_16 {
    left: 255px;
}/* id _position_x 代表每一个分块 */
#_position_1 {
    background-position: 0px 0px;
}#_position_2 {
    background-position: -85px 0px;
}#_position_3 {
    background-position: -169px 0px;
}#_position_4 {
    background-position: -253px 0px;
}#_position_5 {
    background-position: 0px -84px;
}#_position_6 {
    background-position: -85px -84px;
}#_position_7 {
    background-position: -169px -84px;
}#_position_8 {
    background-position: -253px -84px;  
}#_position_9 {
    background-position: 0px -168px;
}#_position_10 {
    background-position: -85px -168px;
}#_position_11 {
    background-position: -169px -168px; 
}#_position_12 {
    background-position: -253px -168px;
}#_position_13 {
    background-position: 0px -252px;
}#_position_14 {
    background-position: -85px -252px;
}#_position_15 {
    background-position: -169px -252px; 
}#_position_16 {
    opacity: 0;
    background-position: -253px -252px;
    background-image: none;
}



JavaScript:/*
    项目:拼图游戏
*/window.onload = function() {
    create_pic();
    document.getElementById("restart").addEventListener("click", random_pos);
    document.getElementById("change_image").addEventListener("click", change_img);
};/* 检查产生的随机数列是否是合理的,因为有可能出现恢复不到原图的情况 */
function check_random_isValid() {
    var count = 0;
    for (var i = 0; i < 16; i++) {
        for (var j = i+1; j < 16; j++) {
            if (random_arr[j] < random_arr[i]) {
                count++;
            }
        }
    }
    return count%2===0;
}/* 产生拼图 */
function create_pic() {
    picture = document.getElementById("picture");
    for (var i = 1; i <= 16; i++) {
        var part = document.createElement("div");
        part.addEventListener("click", pic_move);
        part.className = "picture_part" + count + " position_"+i;
        picture.appendChild(part);
        part.id = "_position_"+i;
    }
}/* 改变图片 */
var count = 0;
function change_img(event) {
    if (count < 1) count++;
    else return;
    for (var i = 0; i < 16; i++) {
        picture.childNodes[i].className += " picture_part" + count;
    }
}/* 产生随机数列定义位置 */
function random_pos(event) {
    document.getElementById("result").innerText = "";
    /* 产生随机数列前先将拼图块对应的位置复位 */
    for (var k = 1; k <= 16; k++) {
        document.getElementById("_position_"+k).className="picture_part"+count+" position_"+k;
    }
    var part = document.getElementById("picture").childNodes;
    random_arr = [];
    for (var j = 0; j < 15; j++) {
        random_arr[j] = j+1;
    }
    /* 利用sort和cmp进行随机打散 */
    function cmp() { return 0.5-Math.random(); }
    while(1) {
        random_arr.sort(cmp);
        if (check_random_isValid()) {
            break;
        }
    }
    /* 通过更改类名来改变位置 */
    for (var i = 0; i < 15; i++) {
        part[i].className = "picture_part" + count + " position_" + random_arr[i];
    }
}/* 点击图片触发的事件处理器 */
function pic_move(event) {
    var blank_pic_offset = document.getElementById("_position_16");
    var blank_pic_offset_top = blank_pic_offset.offsetTop;
    var blank_pic_offset_left = blank_pic_offset.offsetLeft;
    var _offset_top = this.offsetTop;
    var _offset_left = this.offsetLeft;
    /* 判断点击的图片块是否与空格块相邻 */
    if ((Math.abs(blank_pic_offset_top-_offset_top) == 85 && blank_pic_offset_left == _offset_left) ||
        (Math.abs(blank_pic_offset_left-_offset_left) == 85 && blank_pic_offset_top == _offset_top)) {
        var str = blank_pic_offset.className;
        blank_pic_offset.className = this.className;
        this.className = str;
        check(); // 检查是否还原原图
    }
}/* 检查是否还原原图 */
function check() {
    for (var i = 1; i <= 16; i++) {
        var item = document.getElementById("_position_"+i);
        if (item.className != "picture_part" + count +" position_"+i &&
            item.className != "picture_part0" + " position_" + i + " picture_part1") {
            document.getElementById("result").innerText = "Continue...";
            return;
        }
    }
    document.getElementById("result").innerText = "You Win!";
}