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

来源:互联网 发布:手机淘宝怎么秒杀成功 编辑:程序博客网 时间:2024/06/05 11:45

转自http://bbs.9ria.com/thread-63206-1-1.html


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

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


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

a(1,2) , b(1,7)

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

其次是纵向检测:
  1. a(1,1) , b(4,1)

  2. private function vertical(a:Point,b:Point):Boolean 
  3. {
  4.         if (a.x == b.x && a.y == b.y) return false;
  5.         var y_start:int = a.x < b.x?a.x:b.x;
  6.         var y_end:int = a.x < b.x?b.x:a.x;
  7.         for (var i:int = y_start + 1; i < y_end; i ++ ) 
  8.         {
  9.                 if (mapData[i][a.y] != 0) 
  10.                 {
  11.                         return false;
  12.                 }
  13.         }
  14.         return true;
  15. }
复制代码
一个拐角的检测
如果一个拐角能连通的话,则必须存在C、D两点。其中C点的横坐标和B相同,纵坐标与A相同,D的横坐标与A相同,纵坐标与B相同
  1. * a(4,2) , b(2,7)
  2. * c(2,2) , d(4,7)
  3. private function oneCorner(a:Point,b:Point):Boolean 
  4. {
  5.         var c:Point = new Point(b.x, a.y);
  6.         var d:Point = new Point(a.x, b.y);
  7.         //判断C点是否有元素                
  8.         if (mapData[c.x][c.y] == 0) 
  9.         {
  10.                 var path1:Boolean = horizon(b, c) && vertical(a, c);
  11.                 return path1;
  12.         }
  13.         //判断D点是否有元素
  14.         if (mapData[d.x][d.y] == 0) 
  15.         {
  16.                 var path2:Boolean = horizon(a, d) && vertical(b, d);
  17.                 return path2;
  18.         }else 
  19.         {
  20.                 return false;
  21.         }
  22.                         
  23. }

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


Line类结构如下:
  1. package  
  2. {
  3.         import flash.display.Sprite;
  4.         import flash.geom.Point;
  5.         
  6.         /**
  7.          * ...
  8.          * @author icekiller
  9.          */
  10.         public class Line extends Sprite
  11.         {
  12.                 public var a:Point;
  13.                 public var b:Point;
  14.                 public var direct:int; //连线方向1:水平直连 0:垂直直连
  15.                 public function Line(a:Point,b:Point,direct:int) 
  16.                 {
  17.                         this.a = a;
  18.                         this.b = b;
  19.                         this.direct = direct;
  20.                 }
  21.                 
  22.         }

  23. }

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



(6) 
图(6)
(7)水平延伸 
图(7)水平延伸
图8.jpg 
图(8)求得水平延伸公共范围

从图(8)可以看出,左边缘(第零列)有一对叉可以直连,所以红色棋子是可以“二折连通”的!
  1.         
  2. private function scan(a:Point,b:Point):Vector.<Line> 
  3. {
  4.         linkList = new Vector.<Line>();
  5.         //检测a点,b点的左侧是否能够垂直直连
  6.         for (var i:int = a.y; i >= 0; i -- ) 
  7.         {
  8.                 if (mapData[a.x][i] == 0 && mapData[b.x][i] == 0 && vertical(new Point(a.x,i),new Point(b.x,i))) 
  9.                 {
  10.                         linkList.push(new Line(new Point(a.x,i),new Point(b.x,i),0));
  11.                 }
  12.         }
  13.         //检测a点,b点的右侧是否能够垂直直连
  14.         for (i = a.y; i < col;i ++ ) 
  15.         {
  16.                 if (mapData[a.x][i] == 0 && mapData[b.x][i] == 0 && vertical(new Point(a.x,i),new Point(b.x,i))) 
  17.                 {
  18.                         linkList.push(new Line(new Point(a.x,i),new Point(b.x,i),0));
  19.                 }
  20.         }
  21.         //检测a点,b点的上侧是否能够水平直连
  22.         for (var j:int = a.x; j >= 0; j -- ) 
  23.         {
  24.                 if (mapData[j][a.y] == 0 && mapData[j][b.y] == 0 && horizon(new Point(j,a.y),new Point(j,b.y))) 
  25.                 {
  26.                         linkList.push(new Line(new Point(j, a.y), new Point(j, b.y), 1));
  27.                 }
  28.         }
  29.         //检测a点,b点的下侧是否能够水平直连
  30.         for (j = a.x; j < row; j ++ ) 
  31.         {
  32.                 if (mapData[j][a.y] == 0 && mapData[j][b.y] == 0 && horizon(new Point(j,a.y),new Point(j,b.y))) 
  33.                 {
  34.                         linkList.push(new Line(new Point(j, a.y), new Point(j, b.y), 1));
  35.                                 
  36.                 }
  37.         }
  38.                         
  39.         return linkList;
  40. }

取出LinkList里面的线,测试A与B到该线的两点是否连通
  1.                 
  2. private function twoCorner(a:Point,b:Point):Boolean 
  3. {
  4.         var ll:Vector.<Line> = scan(a, b);
  5.         if (ll.length == 0) 
  6.         {
  7.                 return false;
  8.         }
  9.         for (var i:int = 0; i < ll.length; i ++ ) 
  10.         {
  11.                 var tmpLine:Line = ll[i];
  12.                 if (tmpLine.direct == 1) 
  13.                 {
  14.                                         
  15.                         if (vertical(a,tmpLine.a) && vertical(b,tmpLine.b)) 
  16.                         {
  17.                                 return true;
  18.                         }
  19.                 }else if (tmpLine.direct == 0) 
  20.                 {
  21.                         if (horizon(a, tmpLine.a) && horizon(b, tmpLine.b)) 
  22.                         {
  23.                                                 return true;
  24.                         }
  25.                 }
  26.         }
  27.         return false;
  28. }

前面的函数有以下这个总的调用函数来调用,传入两个点,就可以判断这两个点是否符合连连看的算法了:
  1.                 
  2. //总函数
  3. private function checkLink(a:Point,b:Point):Boolean 
  4. {
  5.                 
  6.         if (a.x == b.x && horizon(a, b)) 
  7.         {
  8.                 return true; 
  9.         } 
  10.         if (a.y == b.y && vertical(a, b))
  11.         {
  12.                 return true;
  13.         }  
  14.         if (oneCorner(a, b))
  15.                 {
  16.                        return true;  
  17.          }
  18.         else 
  19.         {
  20.                 return twoCorner(a, b);
  21.         }
  22. }


0 0
原创粉丝点击