C++入门教程(23)深度优先,广度优先(连连看判断是否可以消除)

这篇博客介绍了如何使用C++实现连连看游戏的消除功能,通过深度优先搜索(DFS)和广度优先搜索(BFS)策略。博主探讨了搜索下一个节点的方法、避免重复查找的策略、记录已找到路径的方式,并给出了相关代码示例。在连连看规则基础上,解释了如何处理边界情况和转折次数限制,确保搜索的正确性。最后,博主提出对于DFS和BFS在实际应用中的优势和应用场景的思考。
摘要由CSDN通过智能技术生成

最近看一个人实现连连看是否可以消除的核心代码,几分钟就写完了,手痒痒自己写了一遍

需求:实现一个函数,输入两个选中的块,判断是否可以消除

连连看规则,两个相同的块可以消除,但是需要满足以下条件,

        两个块的连线上不能有其他块

        连线的转折次数不能超过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+&
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱我呦呦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值