当前位置:文档之家› Java下连连看算法

Java下连连看算法

两点之间只需要一条直线连接:
( 注意:为了简单省事,我们用java.awt 包中的
Poin(x, y)t 来描述二维数组中元素的坐标,但是有
一点要特别小心,x 和y 与二维数组中元素的下
标值恰好相反,如左上图中A 的下标为
array[1][0] ,Point 的描述却是为Point(0, 1) ,
如果不注意这一点,程序会出错的。

)
两点之间需要两条直线连接:
如上图, A 、 B 两点如果需要两条直线连接起
来,有可能有两种方式,于是,我们可以巧妙的构
建一个 C 点和一个 D 点,并且规定C 点的横
坐标为 A 点的横坐标,C 点的纵坐标为B 点
的纵坐标, D 点的横坐标为B 点的横坐标,D
点的纵坐标为A 点的纵坐标(这一点很重要,因
为 C 、D 决定了AC 、BC 、AD 、BD 的
连线方式),如下图:
如果此时C 点(或D 点)能同时满足AC
(AD )、BC (BD )只需要一条直线相连,
就表示 A 、B 之前能够使用两条直线连接起来,
并且C 点( D 点)为拐点(以后会用上的)
//A 、B 之间有一个拐点
boolean oneCorner(Point a, Point b) {
Point c, d;
boolean isMatch;
c = new Point(a.x, b.y);
d = new Point(b.x, a.y);
if (map[c.x][c.y] == 0) { //C 点上必须没有
障碍
isMatch = horizonMatch(a, c) &&
verticalMatch (b, c);
if (isMatch) {
return isMatch;
}
}
if (map[d.x][d.y] == 0) { //D 点上必须没有
障碍
isMatch = verticalMatch (a, d) &&
horizonMatch (b, d);
( 注意:由于 C 点和 D
点的构建方式确定了 AC 、 BD 永远是竖连线、
BC 、 AD 永远是横
连线 )
两点之间需要三条直线连接:
这种方式是最复杂的了,我们还是先分析一下出现三条直线的所有可能性吧。

( 图 A)
( 图 B :这种方式比较容易忽略掉 )
以上图说明了两点间三条直线的所有可能性,和二条直线的情况相比,拐点是两个,麻烦了一点,但也不难处理。

下面我们来分析一下该怎么处理二个拐点的情况(三条直线)。

由上面的图可以看出, A 、 B 如果要通过三条直线相连,则必须有 C 、 D 两个拐点,如果能确定下 C 、 D ,问题就好解决多了。

怎么样来确定 C 、 D 两点呢?我们以图 A 中的左图为例,在此之前,我们规定 C 点与 A 点
在同一竖线上, D 点与 A 点在同一直线上。

同时,从图中我们也可以看出, A 、 B 两点间如果只能通过三条直线连接起来,则必定有一条直线处于 A 、 B 的横向夹线纵向夹线中(如画圈的线)。

我们假设相等的线为在 A 、 B 两点的横坐标相等、纵坐标为 0~Setting.ROW 构成的区域上 ( 如
图 ) 。

我们先扫描出所有的线,并且我们发现,如果在 A 、 B 构成的区域中存在两个点能构成直线,那么,这条直线就 有可能 是我们需要的直线,我们称此线为符合线,如果符合线的两端( C 、 D 两点)与 A 、 B 两点分别能 AC 、 CD 、 DB 能构成直线的原则,则 AB 间一定可以通过三条直
线连接起来。

(这个可能我描述得不太清楚,但相信你应该不难明白的)
我们把所有找到的符合线保存起来,并且要记录下符合线是横向上的还是纵向上的,然后通过这些找到的符合线,依次和 A 、 B 两点进行判断,一旦找到这样的 C 、 D 两点,能满足 AC 、 CD 、 DB 这三条线上都没有障碍,那么, A 、 B 就可以消除了。

还是用算法来描述一下吧。

首先我们构建一个保存 C 、 D 点的类 Line ,并且要指明 C 、 D 的方向是横向还是纵向。

//Line.java public class Line { public Point a, b;
public int direct; //1 表示横线, 0 表示竖线 public Line() { }
public Line(int direct, Point a, Point b) { this.direct = direct; this.a = a; this.b = b; } }
同时,由于在扫描的过程中,会找到多根符合线,因此,我们可以用 Vector 来保存这些找到的符合线(为了提高效率,也可以使用 LinkedList 来保存)。

扫描两点构成的矩形内有没有完整的空白线段 Vector scan(Point a, Point b) { Vector v = new Vector();
// 从 a, c 连线向 b 扫描,扫描竖线 // 扫描 A 点左边的所有线 for (int y = a.y; y >= 0; y--) {
if (map[a.x][y] == 0 && map[b.x][y] == 0 &&
verticalMatch(new Point(a.x, y), new Point(b.x, y))) { // 存在完整路线
v.add(new Line(0, new Point(a.x, y), new Point(b.x, y))); } }
// 扫描 A 点右边的所有线
for (int y = a.y; y < COLUMN; y++) { if (map[a.x][y] == 0 && map[b.x][y] == 0 &&
verticalMatch(new Point(a.x, y), new Point(b.x, y))) { // 存在完整路线
v.add(new Line(0, new Point(a.x, y), new Point(b.x, y))); } }
// 从 a, d 连线向 b 扫描,扫描横线
// 扫描 A 点上面的所有线 for (int x = a.x; x >= 0; x--) {
if (map[x][a.y] == 0 && map[x][b.y] == 0 &&
horizonMatch(new Point(x, a.y), new Point(x, b.y))) {
v.add(new Line(1, new Point(x, a.y), new Point(x, b.y))); } }
// 扫描 A 点下面的所有线
for (int x = a.x; x < ROW; x++) { if (map[x][a.y] == 0 && map[x][b.y] == 0 &&
horizonMatch(new Point(x, a.y), new Point(x, b.y))) {
v.add(new Line(1, new Point(x, a.y), new Point(x, b.y))); } } return v; }
现在,我们对所有找到的符合线进行判断,看看 AC 、 DB 是否同样也可以消除
段,无解 return false; }
for (int index = 0; index < vector.size(); index++) {
Line line = (Line) vector.elementAt(index); if (line.direct == 1) { // 横线上的扫描段,找到了竖线
if (verticalMatch(a, line.a) &&
verticalMatch(b, line.b)) { // 找到了解,返回 return true; } }
else { // 竖线上的扫描段,找到了横线 if (horizonMatch(a, line.a) && horizonMatch(b, line.b)) { return true; } } }
return false; }
消除该两个元素时,只需要将两个元素的值置为 0 即可。

更多的功能:自动寻找匹配的点
现在,算法基本上是实现了,但是,为了使游戏更丰富,我们还需要实现更多的功能,现在,我们添加一个自动寻找匹配的点的功能。

该功能需要分两步走:
第一步,从左上向右下搜索二维数组中第一个值不为0 的元素A ,找到该点后,然后再从该点向后找到一个值与该点值相等的元素B ,然后对这两个元素进行是否可消除的判断,如果可以消除,则说明该两点匹配,如果不能消除,则继续寻找与A 点值相等的B 点,如果找不到 B 点,则寻找下一个 A 点,依次下去,直到找不到这个 A 点,这就表时地图上已经不存在可消除的点了,我们用伪算法描述如下:
找到第一个 A 点
while (A 点存在时) {
while ( 能找到与A 点值相等的B 点) {
if (Match(A, b)) {
返回找到的AB 点;
}
}
寻找下一个 A 点
;
}
找不到点;
更多的功能:刷新地图
刷新地图的功能其实非常简单,只是需要将二维数组中现有的元素打乱后然后放回这个二维数组):。

相关主题