这几天正值windows developer preview发布,我就尝了个鲜,结果博文的一些材料就耽误了收集,深表歉意啊。
之前写了连连看的地图生成算法,其中某些方法是网上比较常见的,有的貌似还没发现过,就算是一个整理吧。今天的寻路算法同样是一个整理。
首先,我们要规定连连看认为两个图片是可消除的的条件是什么:
1、两个图片是同一类型的图片;
2、两个图片之间存在通路且此通路是由不多于三条的直线组成(通路是由没有图片的部分组成的);
所以无论是什么算法第一步是判断是否是同类图片,然后是真正的寻路算法。
我们要提的第一个方法是递归—回溯法,相信很多寻路或者遍历问题的算法都会用到递归。其基本的思想在连连看游戏中可以这样表达:
从被选中的两个点中的一个出发,向着任意方向(除了来的方向)前进,直到无法前进或者达到约束条件(即超过三条直线)前没能到达另一选中点,则按栈回溯,重新移动(有点类似图的深度优先遍历算法)。如果遍历晚全部可移动区域仍无法到达另一点则失败。
我们可以看做一个小虫子在走迷宫,但是这个小虫比较聪明,同一错误的路不会走第二次。但是我们还可以使小虫更聪明些,比如让小虫优先向着目的地方向的通路前进,让小虫尽量先走直线以达到使用直线最少等。
但是递归回溯的方法实现复杂,即使优化后效率也较低下,所以我们可以来看另一个方法。
第二个方法我叫它“关键点联通法”,所谓关键点就是联通两个点所用直线的交点。
我们先采用分而治之的思想,把问题分成一线联通,两线联通和三线联通来分析。
我们先假设有一函数(方法):A(),可以用来判断在同一直线上的两点是否联通,如图1
·图1
A()的实现是比较简单的,只需看数组中从一点到另一点上的元素是否都为空即可。
现在看两条直线的情况,如图2
·图2
我们注意图中的矩形虚线框,加入我们要判断A,B两点是否联通,则可以通过判断A、B到矩形的同一顶点是否联通,并且该顶点为空来判断。且两点要么能够组成一个矩形,要么处于同一直线上。
最后是三条直线的情况,地图中任意相对位置的两点在无干扰物的情况下都可以通过三条直线连接。如图3
·图3
我们先从A点向任意方向出发,找到可以和他直接相连(即用一条直线相连)的空白点X,然后用此点的横坐标(纵坐标)和B点的纵坐标(横坐标)组成一个点Y,看点Y是否为空且与X,B均联通(也可看成这个点X与B两线相连的判断——递归哦!)。
我们观察图3从A点出发,无论先向哪个方向,均可能顺利到达B点。但是第一次转向的时候必定是向着B点的方向转向。可以利用这个性质对算法稍微进行优化。
以上就是第二种判断方法,我认为朋友们看完一定会有所察觉,其实这个方法就是在递归调用两点直连的判断,我之所以称之为关键点法就是通过找到关键的几个点来减少循环的次数以达到节省时间的目的。
最后一个方法,我叫它“井”子法。
先看图
“井”子法也要建立在一线联通判断的基础上,其中一线联通和两线联通的判断基本和第二个方法相同。
三线联通的时候,我们首先获得A点在水平方向的可触及点(即在水平直线上能与A一线联通的空白点)的范围,例如是0-4,再获得B在水平方向上的可触及点,例如是3-5,然后让A的可触及点与B的可触及点进行一线连接判断,如果成功,则代表A、B可以三线连接。我们还可以将A,B的可触及点取交集后,再判断是否可以直线联通。
总结:方法一虽然繁琐且低效,但是却是十分重要的基础算法(汉诺塔,八皇后,数独。。。。都有用到其中思想),因此捎带提了一下。
重点说方法二、三,这两个方法思想上大同小异,一个是从一点出发,一个是从两边共同出发寻路。朋友们不难发现,两个算法的三线联通判断中其实都已经包含了对一二线的判断,只需在编码是注意一下就好。
算法二可以加入一些优化代码来保证三线时第一个拐点拐的方向,而在算法三中直接就可以确定拐点方向,这个三相对于二一个明显的优势。
在网上看了很多连连看的算法,其思想也是大同小异,本文算不得原创只是对大家智慧的粗劣总结。希望大家有什么好的算法多和我交流,谢谢!
(想了一下还是决定不贴代码出来了,虽然有的时候看代码比较直观,也省的我写这么多字,但是我还是希望有需要的朋友亲手敲一敲,才会有感觉!)