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

function cmp() {
return 0.5-Math.random();
}
1
2
3
但是,生成的拼图不一定能恢复到原来的样子,必须进行验证,如果没有通过验证,则需要重新生成随机数组,对于这个验证,可以详见这篇博文: 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>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
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!";
}

拼图游戏js的更多相关文章

  1. 拼图游戏(js,C#,java三种语言)

    <html> <head> <meta charset="utf-8"> <style type="text/css" ...

  2. 利用Vue.js实现拼图游戏

    之前写过一篇<基于Vue.js的表格分页组件>的文章,主要介绍了Vue组件的编写方法,有兴趣的可以访问这里进行阅读:http://www.cnblogs.com/luozhihao/p/5 ...

  3. Vue.js实现拼图游戏

    Vue.js实现拼图游戏 之前写过一篇<基于Vue.js的表格分页组件>的文章,主要介绍了Vue组件的编写方法,有兴趣的可以访问这里进行阅读:http://www.cnblogs.com/ ...

  4. html+css+js实现网页拼图游戏

    代码地址如下:http://www.demodashi.com/demo/14449.html 项目描述 使用 html+js+css 实现一个网页拼图游戏,可支持简单,中等,困难三种难度. 演示效果 ...

  5. 原生JS实现拼图游戏

    最近无聊,练练原生JS:实现拼图游戏.两种玩法:第一种是单击元素进行交换位置:第二种是拖拽元素进行位置交换.首先需要上传图片并进行回显(需要用到FileReader):下面是部分截图: 可以自行设置切 ...

  6. Flexbox + js实现滑动拼图游戏

    滑动拼图就是把一张图片分成几等份,打乱顺序(下图),然后通过滑动拼凑成一张完整的图片. 要实现一个拼图游戏,需要考虑怎样随机的打乱顺序,怎样交换两张图片的位置,等等.但是,使用了Flexbox布局以后 ...

  7. JavaScript写一个拼图游戏

    拼图游戏的代码400行, 有点多了, 在线DEMO的地址是:打开: 因为使用canvas,所以某些浏览器是不支持的: you know: 为什么要用canvas(⊙o⊙)?  因为图片是一整张jpg或 ...

  8. 微信小程序开发的游戏《拼图游戏》

    微信小程序开发的游戏<拼图游戏> 代码直接考进去就能用 pintu.js // pintu.js Page({ /** * 页面的初始数据 */ data: { }, initGame: ...

  9. 一款html拼图游戏详解

    本文是爱编程原创翻译,转载请看清文末的转载要求,谢谢合作! 游戏介绍 这篇文章是献给web游戏开发者用简单的开发工具开发一款游戏.此文介绍了用html.css.javascript只需简单和几个步骤开 ...

随机推荐

  1. L1-013 计算阶乘和

    对于给定的正整数N,需要你计算 S=1!+2!+3!+...+N!. 输入格式: 输入在一行中给出一个不超过10的正整数N. 输出格式: 在一行中输出S的值. 输入样例: 3 输出样例: 9   #i ...

  2. linux free 理解

    free命令:显示Linux系统中物理内存.buffer/cache.swap的使用情况. virtual-machine:~$ free total used free shared buffers ...

  3. java.lang.NoClassDefFoundError: Could not initialize class org.jfree.chart.JFreeChart

    最近在进行利用jfreechart生成图表时发现,项目在本地运行的好好的,一部署到服务器(linux系统)上就不行,报这样的错误: java.lang.NoClassDefFoundError: Co ...

  4. select 从应用层到内核实现解析

    在一个应用中,如果需要读取多个设备文件,这其中有多种实现方式: 1.使用一个进程,并采用同步查询机制,不停的去轮询每一个设备描述符,当设备描述符不可用时,进程睡眠. 2:使用多个进程或者线程分别读取一 ...

  5. Android_ndk_jni_hello-jni_hacking

    /*************************************************************************** * Android_ndk_jni_hello ...

  6. liunx用户管理的基本命令

    1.passwd   修改用户密码 2.useradd 用户组名         增加用户组 3.su 用户名     切换用户名 4.usermod   用户更改 5.userdel    用户删除

  7. Executor 框架

    Java的线程既是工作单元,也是执行机制.从JDK5开始,把工作单元与执行机制分离开来.工作单元包括Runnable和Callable,而执行机制由Executor框架提供. Executor 框架简 ...

  8. Windows环境下搭建Nginx和多版本PHP共存

    PHP版本众多,彼此之间兼容性不好,不同程序经常需要的不同版本的PHP版本.这里介绍如何使用NGINX让不同版本的PHP共存. 软件下载地址 与nginx整合的php需要选择Non Thread Sa ...

  9. FSTConfiguration 高性能序列化框架FST

    转自:https://blog.csdn.net/z69183787/article/details/53005961 fst是完全兼容JDK序列化协议的系列化框架,序列化速度大概是JDK的4-10倍 ...

  10. Vue中的“混合”——mixins使用方法

    混合是一种灵活的分布式复用 Vue 组件的方式.混合对象可以包含任意组件选项.以组件使用混合对象时,所有混合对象的选项将被混入该组件本身的选项.当组件和混合对象含有同名选项时,这些选项将以恰当的方式混 ...