30多行js代码写一个M*N拼图游戏 (2011-12-20)

发布时间:2011-12-20 21:01:52

刚写过一篇《20多行js代码写一个最简单的3x3拼图游戏》,受zswang的启发下改进了代码,现在做了一个任意M行N列(M,N大于等于2)的拼图,js代码30多行。

先上图:

30多行js代码写一个M*N拼图游戏

玩法:方向键,不用解释了。

直接体验就轻轻点击这里

保证拼图有解的方法主要有2种:

  1. 从结局开始移动若干次,浅显易懂,但是空格不在末尾了,如果要把空格移回末尾,还要多两个循环;
  2. 用算法检测随机开局是否有解,如果无解则调整为有解或重新开局。

本篇采用了方法2,使用的算法叫做逆序和,保证有解、且空格在末尾。

关于开局的生成方法有3种:

  1. 数组随机排序。
  2. 模拟洗牌算法。
  3. 从结局开始进行若干次随机方向的移动。

本篇使用算法2,《20多行js代码写一个最简单的3x3拼图游戏》使用的是算法1,zswang的拼图使用算法3。

数组随机排序的效率可能不好,所以改成模拟洗牌算法,循环随机交换。

另外,我加上了很方便的layout()和replay()函数,可以立即重新开始、立即切换布局。

<div id="t1" style="border:1px solid black; padding:5px; display:inline-block;"></div>
<script>
var t1=document.getElementById("t1");
function layout(M,N){
	R=M; C=N; r=R-1; c=C-1; D=[]; n=R*C-1;
    w = (n+'').length;
    rgx = new RegExp('(.{'+(w*C+c-1)+'}),','g');
    space = new Array(w+1).join('_');
    zero = new Array(w).join(0);
	replay();
}
function replay(){
	i=n;
    while(i--){
        D[i]=(zero+(i+1)).slice(-w);
    }
    D[n] = space;
    ok = D+'';
	while(++i<n){
        j=D[rnd = Math.random()*(n-1)|0];
        D[rnd]=D[i];
        D[i]=j;
    }
    for(i=0,k=0;i<n;i++)
        for(j=i+1;j<n;j++)
            D[i]>D[j] && (k=1-k);
    k && (i=D[n-2]) && (D[n-2]=D[n-1]) && (D[n-1]=i);
    t1.innerHTML = (D+'').replace(rgx,'$1<br>');
}
function move(dir){
    if (dir>=0&&dir<4) {
        k = [[0,1],[1,0],[0,-1],[-1,0]][dir], r2 = r+k[0], c2 = c+k[1];
        if (r2+1 && r2<R && c2+1 && c2<C)
        return D[r*C+c] = D[r2*C+c2],
            D[(r=r2)*C+(c=c2)] = space,
            t1.innerHTML = (D+'').replace(rgx,'$1<br>');
    }
}
document.onkeyup = function (e){
    if(move((e||window.event).keyCode-37) && (D+'')==ok && alert('YOU WIN !'));
}
layout(4,4);
</script>

补充:样式美化版

<style type="text/css">
#jigsaw {width:141px;border:solid 1px #666;text-align:center;font-size:22px;line-height:40px;padding:5px 0 0 5px;}
#jigsaw > div {width:40px;height:40px;margin:0 5px 5px 0;border:solid 1px #666;display:inline-block;cursor:default;}
#replay {font-size:16px;}
#success {font-size:16px;color:green;display:none;}
</style>

<div id="jigsaw"></div>
<p>
<select id="layoutM"></select>x<select id="layoutN"></select>
<button id="replay" type="button">再来一局</button>
<span id="success">拼图成功!</span>
</p>

<script>
!function (){
	var R,C,r,c,D,ok;
	function $$(id){return document.getElementById(id);}
	function replay(){
		R=+$$("layoutM").value; C=+$$("layoutN").value; r=R-1; c=C-1; D=[];
		$$('jigsaw').style.width = C*47+'px';
		var n=R*C-1,i=n,j,k;
		while(i--)D[i]=i+1;
		D[n] = 0;
		ok = D+'';
		while(++i<n){
			j=D[rnd = Math.random()*(n-1)|0];
			D[rnd]=D[i];
			D[i]=j;
		}
		for(i=0,k=0;i<n;i++)
			for(j=i+1;j<n;j++)
				D[i]>D[j] && (k=1-k);
		k && (i=D[n-2]) && (D[n-2]=D[n-1]) && (D[n-1]=i);
		while(ok == D+'')return replay();
		v();
		$$('success').style.display='none';
	}
	function v(){
		$$('jigsaw').innerHTML=(D+'').replace(/(\d+)(\D*)/g,'<div>$1</div>').replace(/\b0\b/,' ');
	}
	function move(dir){
		if (dir>=0&&dir<4) {
			var k = [[0,1],[1,0],[0,-1],[-1,0]][dir], r2 = r+k[0], c2 = c+k[1];
			if (r2+1 && r2<R && c2+1 && c2<C)
			return D[r*C+c] = D[r2*C+c2], D[(r=r2)*C+(c=c2)] = 0, v(), 1;
		}
	}
	document.onkeyup = function (e){
		move((e||window.event).keyCode-37) && (D+'')==ok && ($$('success').style.display='inline');
	};
	$$("replay").οnclick=replay;
	$$("layoutM").innerHTML = $$("layoutN").innerHTML = '23456789'.replace(/./g,'<option value="$&">$&</option>');
	$$("layoutM").value = $$("layoutN").value = '4';
	$$("layoutM").onchange = $$("layoutN").onchange = replay;
	replay();
}();
</script>

在线试玩点击这里

posted @ 2022-11-23 21:10  IginCui  阅读(134)  评论(0编辑  收藏  举报