[转]连连看核心算法详解

[url]http://bbs.9ria.com/viewthread.php?tid=63206[/url]

最近做了个连连看游戏,综合网上各种不同的思路,整理出了个人认为大家都比较好理解的一套思路。

游戏规则:很简单,就是点中两个互相匹配并且可以通过不多于两个折点的折线连在一起的方块后,这两个方块就可以消掉。
(说明:下面的行和列按照现实的行和列,并不是按照flash坐标系的坐标,请大家按需转换)

连通算法:
1.直连型
2.一折型
3.两折型

下面我们来分析每一种情况:
直连型
直连性又分为两种情况:横向直连,纵向直连。
首先是横向检测:

[img]http://dl.iteye.com/upload/attachment/440498/fe84155b-5c86-3430-ad27-cd2ade76c2d6.jpg[/img]


a(1,2) , b(1,7)
private function horizon(a:Point,b:Point):Boolean
{
if (a.x == b.x && a.y == b.y) return false; //如果点击的是同一个图案,直接返回false;
var x_start:int = a.y < b.y?a.y:b.y; //获取a,b中较小的y值
var x_end:int = a.y < b.y?b.y:a.y; //获取a,b中较大的值
//遍历a,b之间是否通路,如果一个不是就返回false;
for (var i:int = x_start + 1; i < x_end;i ++ )
{
if (mapData[a.x][i] != 0)
{
return false;
}
}
return true;
}

其次是纵向检测:

[img]http://dl.iteye.com/upload/attachment/440500/8250951b-d00f-373e-aa63-08d081fc9c44.jpg[/img]


a(1,1) , b(4,1)

private function vertical(a:Point,b:Point):Boolean
{
if (a.x == b.x && a.y == b.y) return false;
var y_start:int = a.x < b.x?a.x:b.x;
var y_end:int = a.x < b.x?b.x:a.x;
for (var i:int = y_start + 1; i < y_end; i ++ )
{
if (mapData[i][a.y] != 0)
{
return false;
}
}
return true;
}


一个拐角的检测
如果一个拐角能连通的话,则必须存在C、D两点。其中C点的横坐标和B相同,纵坐标与A相同,D的横坐标与A相同,纵坐标与B相同

[img]http://dl.iteye.com/upload/attachment/440502/8a4325b7-3ecd-3829-9083-37003c52b2c7.jpg[/img]


* a(4,2) , b(2,7)
* c(2,2) , d(4,7)
private function oneCorner(a:Point,b:Point):Boolean
{
var c:Point = new Point(b.x, a.y);
var d:Point = new Point(a.x, b.y);
//判断C点是否有元素
if (mapData[c.x][c.y] == 0)
{
var path1:Boolean = horizon(b, c) && vertical(a, c);
return path1;
}
//判断D点是否有元素
if (mapData[d.x][d.y] == 0)
{
var path2:Boolean = horizon(a, d) && vertical(b, d);
return path2;
}else
{
return false;
}

}


两个拐角的检测:
这个比较复杂,如果两个拐角能连通的话,则必须存在图中所示的连线,这些连线夹在A、B的横、纵坐标之间,这样的线就以下这个类存储,direct是线的方向,用0、1表示不同的方向.

[img]http://dl.iteye.com/upload/attachment/440504/5fc37cbc-c988-3a05-8a9b-49b7c3090687.jpg[/img]


Line类结构如下:

package
{
import flash.display.Sprite;
import flash.geom.Point;

/**
* ...
* @author icekiller
*/
public class Line extends Sprite
{
public var a:Point;
public var b:Point;
public var direct:int; //连线方向1:水平直连 0:垂直直连
public function Line(a:Point,b:Point,direct:int)
{
this.a = a;
this.b = b;
this.direct = direct;
}

}

}


从A、B点的横纵两个方向进行扫描,就是Scan函数做的事情,把合适的线用LinkList存起来。
判断是否是二连型的算法需要做两个方向上的扫描:水平扫描和垂直扫描。
先看水平的,首先,要找到棋子往左右可以延伸的范围,这里的延伸是指左右有多少空的位置;
然后,计算水平坐标上两个棋子延伸出来的公共部分;
最后,找公共的水平坐标里有没有可以“垂直直连”的.用图6,7,8说明

[img]http://dl.iteye.com/upload/attachment/440506/2e102fb5-9d23-380c-863d-a635033d2634.jpg[/img]



图(6)

[img]http://dl.iteye.com/upload/attachment/440508/98aa5117-5eee-361a-81e8-efc3ce602073.jpg[/img]

图(7)水平延伸

[img]http://dl.iteye.com/upload/attachment/440510/1cde75b9-38a2-34c1-8114-c85f562b5ae8.jpg[/img]

图(8)求得水平延伸公共范围

[img]http://dl.iteye.com/upload/attachment/440512/93fe25bf-555e-37e6-9971-fb060f256395.jpg[/img]

从图(8)可以看出,左边缘(第零列)有一对叉可以直连,所以红色棋子是可以“二折连通”的!


private function scan(a:Point,b:Point):Vector.<Line>
{
linkList = new Vector.<Line>();
//检测a点,b点的左侧是否能够垂直直连
for (var i:int = a.y; i >= 0; i -- )
{
if (mapData[a.x][i] == 0 && mapData[b.x][i] == 0 && vertical(new Point(a.x,i),new Point(b.x,i)))
{
linkList.push(new Line(new Point(a.x,i),new Point(b.x,i),0));
}
}
//检测a点,b点的右侧是否能够垂直直连
for (i = a.y; i < col;i ++ )
{
if (mapData[a.x][i] == 0 && mapData[b.x][i] == 0 && vertical(new Point(a.x,i),new Point(b.x,i)))
{
linkList.push(new Line(new Point(a.x,i),new Point(b.x,i),0));
}
}
//检测a点,b点的上侧是否能够水平直连
for (var j:int = a.x; j >= 0; j -- )
{
if (mapData[j][a.y] == 0 && mapData[j][b.y] == 0 && horizon(new Point(j,a.y),new Point(j,b.y)))
{
linkList.push(new Line(new Point(j, a.y), new Point(j, b.y), 1));
}
}
//检测a点,b点的下侧是否能够水平直连
for (j = a.x; j < row; j ++ )
{
if (mapData[j][a.y] == 0 && mapData[j][b.y] == 0 && horizon(new Point(j,a.y),new Point(j,b.y)))
{
linkList.push(new Line(new Point(j, a.y), new Point(j, b.y), 1));

}
}

return linkList;
}

取出LinkList里面的线,测试A与B到该线的两点是否连通

private function twoCorner(a:Point,b:Point):Boolean 
{
var ll:Vector.<Line> = scan(a, b);
if (ll.length == 0)
{
return false;
}
for (var i:int = 0; i < ll.length; i ++ )
{
var tmpLine:Line = ll[i];
if (tmpLine.direct == 1)
{

if (vertical(a,tmpLine.a) && vertical(b,tmpLine.b))
{
return true;
}
}else if (tmpLine.direct == 0)
{
if (horizon(a, tmpLine.a) && horizon(b, tmpLine.b))
{
return true;
}
}
}
return false;
}


前面的函数有以下这个总的调用函数来调用,传入两个点,就可以判断这两个点是否符合连连看的算法了:

//总函数
private function checkLink(a:Point,b:Point):Boolean 
{

if (a.x == b.x && horizon(a, b))
{
return true;
}
if (a.y == b.y && vertical(a, b))
{
return true;
}
if (oneCorner(a, b))
{
return true;
}
else
{
return twoCorner(a, b);
}
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值