最近看一个人实现连连看是否可以消除的核心代码,几分钟就写完了,手痒痒自己写了一遍
需求:实现一个函数,输入两个选中的块,判断是否可以消除
连连看规则,两个相同的块可以消除,但是需要满足以下条件,
两个块的连线上不能有其他块
连线的转折次数不能超过2
处在边界的两个块可以绕出地图一个格子去连线
首先是实现连连看的地图,本例使用的是10X10的地图,边界都为0,真实的块只有8X8
int map[MaxLen][MaxHeight] = {
0,0,0,0,0,0,0,0,0,0,
0,1,0,1,0,1,1,1,1,0,
0,1,3,1,3,1,1,0,0,0,
0,4,0,1,0,1,1,0,0,0,
0,1,0,1,0,1,0,0,0,0,
0,4,0,1,0,1,0,0,0,0,
0,1,0,0,0,1,0,0,0,0,
0,5,1,1,0,1,0,0,0,0,
0,1,5,1,0,1,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
};
0表示可以连线,1是测试的不可连线的值,3,4,5为三对目标块,用来判断是否可以删除
这个程序有几个难点,一个是如何搜索下一个节点,一个是如何避免重复搜索,还有就是如何得到已经找到的路径(需要进行显示线)
搜索下一个节点的实现
由于连线只能是相邻的两个块去连接,所以任意一个目标块为起点,按照四个方向去寻找可搜索的块,直到找到目标块为止。
那么需要定义四个方向,上下左右,
int dir_x[4] = { -1, 1, 0, 0 };
int dir_y[4] = { 0, 0, -1, 1 };
这里用0-3来表示4个方向,每个节点下标和每一个方向对应的dir_x和dir_y进行相加,即可得到相应方向的下一个节点
比如节点 (x1,y1) 遍历4个方向可得到四个新的坐标(x1-1,y1) ,(x1+1,y1) ,(x1,y1-1) ,(x1,y1+1)
避免重复查找
在编码的过程中会发现下面的情况会产生闭环,导致死循环一直查找下去
0,0
0,0
0,0,0,
0,1,0,
0,0,0,
找了一圈发现又回到第一个0搜索,所以需要实现不能有三次转折,也就是十字路口左转,十字路口左转,十字路口左转,三个红路灯以后,你就能再次看到给你指路的那个大聪明了。
//当前节点的查找方向
int dir;
//经过几次转弯
int turn;
为了判断是否有转折需要在块中定义每个块的搜索方向,搜索到当前块经过了几次的转折,只要转折超过3次,非法搜索,这样可以防止闭环的产生。
得到已经找到的路径
为了得到已经找到的路径,需要逆向找到前面的节点,所以节点需要定义一个父节点,用来回退找到前面的所有节点。在实现的过程中,没移动一个方向,就制定当前节点为下个节点的parent
块的定义
class Tile
{
public:
//坐标
int x, y;
//图片值: 0表示已消除 ,大于0表示图片的idx
int value;
//当前节点的查找方向
int dir;
//经过几次转弯
int turn;
//查找深度
int depth;
Tile * parent;
void init()
{
dir = -1;
turn = -1;
depth = -1;
parent = NULL;
}
};
深度优先搜索实现:
//深度优先
bool DFS(Tile tiles[MaxLen][MaxHeight],Tile t1, Tile t2)
{
//两个相同节点不可
if (t1.x == t2.x && t1.y == t2.y)
{
return false;
}
//坐标非法不可
if (t1.x < 0|| t2.x < 0
|| t1.y>= MaxHeight || t2.y>= MaxHeight
|| t1.x >= MaxLen || t2.x >= MaxLen)
{
return false;
}
//深度优先搜索来从一个点找到另一个点
Tile * startTile = &t1;
startTile->depth = 0;
stack<Tile*> sta;
sta.push(startTile);
vector<Tile * > paths;
int result = 0;
//开始节点t1一直向目标节点t2移动 能重合则结束
while (sta.size() > 0)
{
Tile* lastTile = sta.top();
sta.pop();
//尝试寻找
for (int i = 0; i< 4 ; i++)
{
int x = lastTile->x + dir_x[i];
int y = lastTile->y + dir_y[i];
if (x<0 || x >= MaxLen || y < 0 || y>= MaxHeight)
{
continue;
}
Tile *curTile = &tiles[x][y];
//上一个节点转了几次弯
curTile->turn = lastTile->turn;
curTile->dir = i;
curTile->depth = lastTile->depth + 1;
//如果上一个节点方向改变
if (lastTile->dir != curTile->dir)
{
curTile->turn+&