连连看核心算法

转自:http://hi.baidu.com/freezesoul/blog/item/6c8e7a3129d7a819ebc4afb4.html
算法图:

/* 方格数组,高9,宽12。数字0代表空缺位置,其他数字代表 每种图像块,同数字代表同种图像块,规定头尾数组所有元 素只能为0,各数组首尾元素只能为0,以构成一个矩形环绕 空位。用表达式map_ary[0~9][0~12],可以访问这个矩阵的 所有元素。 */ var map_ary:Array = Array();
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2]; map_ary[0] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; map_ary[1] = [0, 1, 3, 4, 7, 7, 8, 9, 1, 6, 6, 2, 0]; map_ary[2] = [0, 3, 5, 6, 8, 8, 9, 2, 5, 7, 0, 7, 0]; map_ary[3] = [0, 4, 2, 6, 7, 5, 4, 3, 0, 0, 0, 2, 0]; map_ary[4] = [0, 7, 5, 9, 3, 8, 0, 8, 0, 5, 4, 5, 0]; map_ary[5] = [0, 5, 3, 4, 0, 0, 7, 5, 4, 2, 4, 2, 0]; map_ary[6] = [0, 1, 0, 3, 6, 0, 0, 6, 2, 4, 5, 6, 0]; map_ary[7] = [0, 6, 0, 0, 0, 7, 0, 4, 3, 8, 9, 4, 0]; map_ary[8] = [0, 2, 5, 6, 7, 4, 3, 9, 7, 9, 8, 1, 0]; map_ary[9] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; /* 排序方法函数,用于Array.sort()方法的调用。编写方法是 function 函数名(第一个元素,第二个元素):Number{如果第一个元素和第二个元素不换位置则返回-1;否则返回1;如果相等就返回0} 使用:数组名.sort(函数名); 下面的这个函数把数组元素的长度作为排序的依据,a.length大于b.length则换位。从而按照此方法排序后的数组是以元素长度升序排列的。 但首先必须确认从数组中取出的的元素具有.length属性,即元素要属于Array或者String,所以被排序的数组是一个嵌套数组。 因为路径集在算法构思时被定义为一个嵌套数组,它的元素是一条条路径,而路径由一个个点组成,一个点由两个坐标组成。 如:paths=[[[1,1],[1,2],[1,3]],[[2,1],[2,2]]] paths.length的值为2,即包含两条路径 paths[0].length的值为3,即第一条路径的长度是3,也即第一条路径包含3个点[1,1],[1,2],[1,3]。 如果要访问到最低层元素可以用类似表达式:paths[0][0][0] 值为1,意为第一条路径的第一个点的第一个坐标。 paths.sort(byLength)后较深层数据顺序不变,只改变paths第一层数据即路径的顺序。结果为:[[[2,1],[2,2]],[[1,1],[1,2],[1,3]]] */ function byLength(a:Array, b:Array):Number {
if (a.length>b.length) {
return 1;
} else if (a.length<b.length) {
return -1;
} else {
return 0;
}
}
/* 遍历序列建立函数,建立一个从v1到v2值中间向两边扩展的序列,以确保遍历从可能出现最短路径的位置开始。 如有一个数列8,6,4,2,0,1,3,5,7,9 现假设要从0的位置开始扩展,得到的数列为0,1,2,3,4,5,6,7,8,9。 现在反过来,原来数列是0,1,2,...,vmax,用(v1+v2)/2作为开始位置。 如:create_sequence(1,8,9)得到的数组是:4,5,3,6,2,7,1,8,0,9。 */ function create_sequence(v1:Number, v2:Number, vmax:Number):Array {
var sequence:Array = Array();
var tmp_ary:Array = Array();
for (var j = 0; j<=vmax; j++) {
sequence.push(j);
}
var i = int((v1+v2)/2);
for (j=0; j vmax-i ? i : vmax-i); j++) {
if (j == 0) {
tmp_ary.push(sequence[i]);
} else {
if (sequence[i+j] != undefined) {
tmp_ary.push(sequence[i+j]);
}
if (sequence[i-j] != undefined) {
tmp_ary.push(sequence[i-j]);
}
}
}
return tmp_ary;
}
/* 下面函数的作用是判断路径是否被阻断(是否不全为0),如果被阻断则返回值true,主函数将继续下一个搜索。 a是个数组用来接收一段路径。其他四个数字是例外的点,因为被判断的两个图块不可能是空缺的,但是 路径的两端包含着这两个点,传递这四个参数的目的是把它们当作是通的。 */ function ary_isBlocked(a:Array, x1:Number, y1:Number, x2:Number, y2:Number):Boolean {
for (var m = 0; m<a.length; m++) {
if (map_ary[a[m][0]][a[m][1]] != 0) {
if ((a[m][0] == x1 && a[m][1] == y1) || (a[m][0] == x2 && a[m][1] == y2)) {
} else {
return true;
}
}
}
return false;
}
/* 下面函数的作用是判断一个点是否被阻断(是否不为0),如果被阻断则返回值true,主函数将继续下一个搜索。 */ function pot_isBlocked(xi:Number, yi:Number, x1:Number, y1:Number, x2:Number, y2:Number):Boolean {
if ((xi == x1 && yi == y1) || (xi == x2 && yi == y2)) {
return false;
}
if (map_ary[xi][yi] != 0) {
return true;
} else {
return false;
}
}
/*
路径寻求函数,前四个参数用来传递两点的坐标,最后一个参数控制是否求得所有路径。该函数的返回值类型为数组类型,
详细内部结构见上述。
*/
function paths(x1:Number, y1:Number, x2:Number, y2:Number, xmax:Number, ymax:Number, isAll:Boolean):Array {
//首先判断两点的图像是否一致 if (map_ary[x1][y1] == map_ary[x2][y2]) {
/* 定义内部变量: p1_x_ary与p2_x_ary存储两点在纵向的两条平行轨道 p1_y_ary与p2_y_ary存储两点在横向的两条平行轨道 px_ary存储架在两平行纵向轨道上的滑竿 py_ary存储架在两平行横向轨道上的滑竿 tmp_ary是一个临时数组,存储临时性的数组数据 points_ary点集数组,每次遍历如果圆满完成,将形成一条通路径 paths_ary路径集数组,每次遍历如果圆满完成,保存points_ary的路径 sequence_ary存储遍历序列 blocked标记性变量,当按点判断滑竿是否被阻断时,如果遇到一点不通则跳出(break)当前循环 并置blocked的值为true,以便再继续(continue)下次遍历 */ var p1_x_ary:Array = Array();
var p1_y_ary:Array = Array();
var p2_x_ary:Array = Array();
var p2_y_ary:Array = Array();
var px_ary:Array = Array();
var py_ary:Array = Array();
var tmp_ary:Array = Array();
var points_ary:Array = Array();
var paths_ary:Array = Array();
var sequence_ary:Array = Array();
var blocked:Boolean;
/* 创建轨道和滑竿 Array.push(表达式)方法:把整个表达式的值作为一个元素加入到数组尾部。 请注意与Array.concat()方法不同之处,见下述。 */ for (var m = 0; m<=xmax; m++) {
p1_x_ary.push([m, y1]);
}
for (m=0; m<=ymax; m++) {
p1_y_ary.push([x1, m]);
}
for (m=0; m<=xmax; m++) {
p2_x_ary.push([m, y2]);
}
for (m=0; m<=ymax; m++) {
p2_y_ary.push([x2, m]);
}
for (m=(y1<y2 ? y1 : y2); m y1 ? y2 : y1); m++) {
px_ary.push([0, m]);
}
for (m=(x1<x2 ? x1 : x2); m x1 ? x2 : x1); m++) {
py_ary.push([m, 0]);
}
/* 如果两点不在同一列时启动px_ary纵向的遍历 */ if (y1 != y2) {
/* 首先建立遍历序列 */ sequence_ary = create_sequence(x1, x2, xmax); for (var i = 0; i<=xmax; i++) {
m = sequence_ary[i];
if (m<x1) {
/* Array.slice(a, b)方法,返回从数组下标为a到数组下标为b-1的元素所构成的新数组。 */ tmp_ary = p1_x_ary.slice(m+1, x1+1);
/* Array.reverse()方法,把目标数组的元素位置倒置 */ tmp_ary.reverse();
if (ary_isBlocked(tmp_ary, x1, y1, x2, y2)) {
/* 如果tmp_ary被阻断则给points_ary点集数组重新分布空间,把原来的数据丢弃。 continue会把程序运行指针转回到循环开始处,下面的语句不会被执行,开始下一次的循环。 continue只会与其最贴近的循环体起作用 */ points_ary = new Array();
continue;
}
/* Array.concat(a:Array)将数组a的元素添加到目标数组的末尾。 如果a=[1,2];b=[[3,4],[5,6]];b.concat(a);b为[[3,4],[5,6],1,2]; 如果a=[[1,2]];b=[[3,4],[5,6]];b.concat(a);b为[[3,4],[5,6],[1,2]]; 请注意与Array.push()方法不同之处,见上述。 */ points_ary = points_ary.concat(tmp_ary);
} else if (m>x1) {
tmp_ary = p1_x_ary.slice(x1, m);
if (ary_isBlocked(tmp_ary, x1, y1, x2, y2)) {
points_ary = new Array();
continue;
}
points_ary = points_ary.concat(tmp_ary);
}
if (y1<y2) {
for (var n = 0; n<px_ary.length; n++) {
if (pot_isBlocked(m, px_ary[n][1], x1, y1, x2, y2)) {
points_ary = new Array();
blocked = true;
/* 按点判断是否被阻断,如果遇到阻断则用break终止 此次按点循环判断,并置blocked标志为true,在跳 出循环后继续滑杆的下一次遍历。break用来终止循环; break只会与其最贴近的循环体起作用。 */ break;
} else {
blocked = false;
}
points_ary = points_ary.concat([[m, px_ary[n][1]]]);
}
if (blocked) {
continue;
}
} else {
for (n=px_ary.length-1; n>=0; n--) {
if (pot_isBlocked(m, px_ary[n][1], x1, y1, x2, y2)) {
points_ary = new Array();
blocked = true;
break;
} else {
blocked = false;
}
points_ary = points_ary.concat([[m, px_ary[n][1]]]);
}
if (blocked) {
continue;
}
}
if (m<x2) {
tmp_ary = p2_x_ary.slice(m+1, x2+1);
if (ary_isBlocked(tmp_ary, x1, y1, x2, y2)) {
points_ary = new Array();
continue;
}
points_ary = points_ary.concat(tmp_ary);
} else if (m>x2) {
tmp_ary = p2_x_ary.slice(x2, m);
tmp_ary.reverse();
if (ary_isBlocked(tmp_ary, x1, y1, x2, y2)) {
points_ary = new Array();
continue;
}
points_ary = points_ary.concat(tmp_ary);
}
paths_ary.push(points_ary);
points_ary = new Array();
if (isAll) {
} else {
break;
}
}
}
/* 如果两点不在同一列时启动py_ary横向的遍历 */ if (x1 != x2) {
sequence_ary = create_sequence(y1, y2, ymax);
for (i=0; i<=ymax; i++) {
m = sequence_ary[i];
if (m<y1) {
tmp_ary = p1_y_ary.slice(m+1, y1+1);
tmp_ary.reverse();
if (ary_isBlocked(tmp_ary, x1, y1, x2, y2)) {
points_ary = new Array();
continue;
}
points_ary = points_ary.concat(tmp_ary);
} else if (m>y1) {
tmp_ary = p1_y_ary.slice(y1, m);
if (ary_isBlocked(tmp_ary, x1, y1, x2, y2)) {
points_ary = new Array();
continue;
}
points_ary = points_ary.concat(tmp_ary);
} else if (y1 != y2) {
continue;
}
if (x1<x2) {
for (n=0; n<py_ary.length; n++) {
if (pot_isBlocked(py_ary[n][0], m, x1, y1, x2, y2)) {
points_ary = new Array();
blocked = true;
break;
} else {
blocked = false;
}
points_ary = points_ary.concat([[py_ary[n][0], m]]);
}
if (blocked) {
continue;
}
} else {
for (n=py_ary.length-1; n>=0; n--) {
if (pot_isBlocked(py_ary[n][0], m, x1, y1, x2, y2)) {
points_ary = new Array();
blocked = true;
break;
} else {
blocked = false;
}
points_ary = points_ary.concat([[py_ary[n][0], m]]);
}
if (blocked) {
continue;
}
}
if (m<y2) {
tmp_ary = p2_y_ary.slice(m+1, y2+1);
if (ary_isBlocked(tmp_ary, x1, y1, x2, y2)) {
points_ary = new Array();
continue;
}
points_ary = points_ary.concat(tmp_ary);
} else if (m>y2) {
tmp_ary = p2_y_ary.slice(y2, m);
tmp_ary.reverse();
if (ary_isBlocked(tmp_ary, x1, y1, x2, y2)) {
points_ary = new Array();
continue;
}
points_ary = points_ary.concat(tmp_ary);
} else if (y1 != y2) {
points_ary = new Array();
continue;
}
paths_ary.push(points_ary);
points_ary = new Array();
if (isAll) {
} else {
break;
}
}
}
if (isAll) {
} else {
/* 如果isAll为false,即只要求得最短路径。 将paths_ary进行排序以便确保最短路径在前面 */ paths_ary.sort(byLength);
/* 返回排序后的第一条路经 */ return [paths_ary[0]]
}
return paths_ary;
}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值