实现算法:
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!";
}