每天一个jquery插件-九宫格拼图
九宫格拼图
九宫格拼图,做起来很有意思,不过这个版本是专属九宫格的,只能提供n宫格的大概思路,后面再想办法搞n*n宫格的拼图!
效果如下
代码部分
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>做拼图游戏</title>
<script src="js/jquery-3.4.1.min.js"></script>
<style>
*{
margin: 0px;
padding: 0px;
user-select: none;
}
#div{
border: 1px solid lightgray;
width: 330px;
height: 330px;
}
.item{
width: 100px;
height: 100px;
overflow: hidden;
float: left;
outline: 1px solid lightgray;
position: absolute;
transition: all 0.2s linear;
}
.img{
background: url(img/1.jpg);
background-position:0 0;
background-repeat: no-repeat;
background-size: 300px 300px;
}
.i0{
background-position: 0px 0px;
}
.i1{
background-position: -100px 0px;
}
.i2{
background-position: -200px 0px;
}
.i3{
background-position: 0px -100px;
}
.i4{
background-position: -100px -100px;
}
.i5{
background-position: -200px -100px;
}
.i6{
background-position: 0px -200px;
}
.i7{
background-position: -100px -200px;
}
.i8{
background-position: -200px -200px;
}
</style>
</head>
<body>
<div id="div"></div>
</body>
</html>
<script>
$(function(){
const arr = [0,1,2,3,4,5,6,7];//每个图块显示的位置
const posrr = [
{
top:6,left:6},{
top:6,left:116},{
top:6,left:226},
{
top:116,left:6},{
top:116,left:116},{
top:116,left:226},
{
top:226,left:6},{
top:226,left:116},{
top:226,left:226},
]//每个图块的定位
var temp = 0;
//获取一个块状序列的数组,必须得有效!
getarr().forEach(item=>{
var $item = $("<div class='item img i"+item+"' data-index='"+temp+"' ></div>");
$item.appendTo($("#div"));
$item.css(posrr[temp])
temp++;
})
//点击方向键,拼图自然跟着动,我的想法是
//每个空余部分都有对应的动作,所以我首先就是找到空缺的位置,然后进行替换动作
$(document).keydown(function(e){
var index = getIndex();
//动作效果无非就是通过方向键控制占有位置向空置位置挪动
//0-1-2
//3-4-5
//6-7-8
if((e.keyCode==87||e.keyCode==38)&&index<6){
//上
thec(index+3,index);
}
if((e.keyCode==65||e.keyCode==37)&&"258".indexOf(index)==-1){
//左
thec(index+1,index)
}
if((e.keyCode==83||e.keyCode==40)&&index>=3){
//下
thec(index-3,index)
}
if((e.keyCode==39||e.keyCode==68)&&"036".indexOf(index)==-1){
//右
thec(index-1,index);
}
})
function getIndex(){
var str = "012345678";
var $items = $(".item").getarr();
$items.forEach(item=>{
var index = item.attr("data-index");
str = str.replace(index,"");
})
return parseInt(str);
}
//进一步优化的替换方式,就是把一个序号位置的替换到新的地方,然后给上新的定位,并且替换掉data-index
//要挪动的块,要挪动的目标位置
function thec(i1,i2){
the(i1).stop().animate(posrr[i2],200);
the(i1).attr("data-index",i2);
}
//一个根据下标返回控制对象的方法
function the(index){
return $(".item[data-index='"+index+"']");
}
//给一个随机顺序的拼图序列,必须经过可解验证
function getarr(){
var flag = true;//为true还是需要循环产生一个新的数组
while(flag){
//随机产生序列
var arr1 =[0,1,2,3,4,5,6,7];
var arr2 = [];
while(arr1.length>0){
var index = Math.floor(Math.random()*arr1.length);
arr2.push(arr1[index]);
arr1.splice(index,1);
}
//然后对序列进行有效验证
var arr3 = arr2;
var counts = 0;
for(var a= 0;a<arr3.length;a++){
for(var b = a;b<arr3.length;b++){
if(arr3[a]>arr3[b]){
counts++;
}
}
}
//因为第九块空置的就是第九块空置的图块,所以逆序数必须为偶数
if(counts%2==0){
flag =false;
console.log("有解");
}else{
console.log("无解");
}
}
return arr2;
}
//一个将dom伪数组的对象转为jquerydom的数组对象
$.prototype.getarr = function(){
var that =this;
var arr = [];
for(var i = 0;i<that.length;i++){
var $dom = $(that[i]);
arr.push($dom);
}
return arr;
}
})
</script>
思路解释
- 首先分析这个东西有哪些属性,同时存在哪些驱动动作,我觉得对编写有必要的参数有这些,一个九宫格从左上角往右下角有各自的顺序应该存在一个数组列表比如九宫格可能会有[2,1,3,4,9,8,6,7,5]这样一组数据,他们的下标表示在那个位置上,里面的数值代表图块是哪一部分,准确来说这是俩属性,一个是当前位置,还有一个是这个图块是整图中第几块。
- 然后后面就好说了,我们随机产生一个乱序的数组,然后挨个确定里面图块是第几块同时他又放在哪就好了。
- 我这里位置是用一个数组管理的,这个比较好计算,但是只做一个九宫格所以写死也没啥
- 然后就是动作效果,通过方向键来控制各图块移动,然后我就想到的是先找到空置的那一块,然后再根据它和方向键的关系就能算出来了,比如你空置的是0,那么左键就是将位于1图块的向0左移动然后更改它的状态,如果是向上就是位于3的图块向0上移动,其他方向确实不行,并且这个挪动是不是感觉有点繁琐,不过我精简了一下实现效果,起始就是两个参数,一个是涉及的空置参数还有就是要移动的参数,这里面都有各自的逻辑关系,不过就不细讲了看代码来的明白写。
- 然后效果全部实现之后,我玩的时候发现还是不行,因为随机放置的图块居然有一半的几率是无解的!然后我又去网上找了下解决方式,后面搞了一个解决办法,不过具体看代码吧,这里比较搞心态,但是弄清楚之后就简单了
- 吃饭!
- 更新于第二天,之前里面的判断是否有解的算法有误,已更新,其实就是判断逆序数有多少个,然后知道缺少的图块与目标位置最少的挪动次数,计算同奇或同偶就行了 ,因为我这里面缺少的图块默认就是第九块,然后空置的也是第九块,他复位所需最少移动次数是0就看做是偶数,然后我的数列中的逆序数为偶数就行了,假如我的初始的空置位置是第八块的地方,那么至少移动一次是奇数,所以逆序数必须是奇数就行了
- 完事!