广度优先搜索:找不到路径,是二维数组中边框的最短路径

问题描述

我尝试编写“圆点圆圈”游戏。游戏的基本思路是,您必须先将蓝点包围,然后再逃脱。每放置一个障碍物(橙色点),蓝色点(“玩家”)就会向边界移动一步。如果您直到他在边界上之前都没有圈出蓝点,您就输了,游戏会重新开始。

因此,我必须在2D UIButton数组上进行 呼吸优先搜索 ,以找到从playerButton到边框的最短路径。

问题:

它通常找不到边界的路径(在控制台中打印“找不到路径!”并重新启动),即使有可能,蓝色圆点也可以到达边界/圆点没有被圈出橙色的点。它也不是走的最短的路径,有时圆点只会循环起来。下来,起来,下来...这很容易取胜。

我的项目:

最好的办法是只download my project(总共300行代码here。然后,您可以用这些模式测试问题:(单击标签上给定的序列按钮/点)

  1. 找不到可能的路径,但有很多路径:(1,2)->(0,3)->(1,4)

  2. 找不到可能的路径,但是有一个路径:(2,2)->(1,3)->(2,4)->(2,5)->(3,5)- >(4,4)->(3,3)

  3. 向上/向下/向上/向上循环:(3,1)->(1,0) ->(3,5)->(4,6)->(4,7)->(5,8)

重要提示:看到这些问题的方式有无限多种,这3种模式只是为了更快地找到问题,您无需多次播放它,直到出现问题为止。此外,您还必须取消注释第94行(possibleNeighbours.shuffle()),因为这会使模式随机化。

如果您不想下载我的整个项目,可以看看我的广度优先搜索方法,该方法返回蓝点必须移至的下一个x和y坐标:

    func findDirection()->String{
    var blockedArr:  [[Bool]] = [[false,false,false],[false,false]] // Can do it like this as its always 9X9
    
    for btnline in btnArr{ //Block all dots which are already occupied
        for btn in btnline{
            if(btn.backgroundColor != defaultColor){
                blockedArr[getX(btn: btn)][getY(btn: btn)] = true
            }
        }
    }
    
    let otheryQueue = otherQueue<Pair>()
    let pair = Pair()
    var possibleNeighbours = findPossibleNeighbours(btn: btnArr[playerX][playerY],blockedArr: blockedArr) //returns array of all possible neighbours of given dot
    print(String(possibleNeighbours.description) + " possibeNeighs beginning" )
   //possibleNeighbours.shuffle() //IMPORTANT: Uncomment this to make it more random
    
    for neighbour in possibleNeighbours{
        if(isOnBorder(point: neighbour)){
            print("Blue dot is on border")
            return neighbour
        }
        pair.setPair(firstValue: neighbour,secondValue: neighbour)
        otheryQueue.enqueue(key: pair)
        blockedArr[getXFromString(string: neighbour)][getYFromString(string: neighbour)] = true
    }
    
    // Start the search
    while(!otheryQueue.isEmpty){
        let pointPair = otheryQueue.dequeue()
        let button = btnArr[getXFromString(string: (pointPair?.getFirst())!)][getYFromString(string: (pointPair?.getFirst())!)]
        possibleNeighbours = findPossibleNeighbours(btn: button,blockedArr: blockedArr)
        for neighbour in possibleNeighbours{
            if isOnBorder(point: neighbour){
                return (pointPair?.getSecond())!
            }
            pair.setPair(firstValue: neighbour,secondValue: (pointPair?.getSecond())!)
            otheryQueue.enqueue(key: pair)
            blockedArr[getXFromString(string: neighbour)][getYFromString(string: neighbour)] = true
        }
    }
    print("No path found!")
    return "-1 -1" //return (-1,-1) position if NO PATH FOUND
}

以下是游戏视图的屏幕截图,可帮助您理解我对(1,2),(0,3),蓝点等的意思:

Screenshot

如有疑问,请询问。

感谢您的帮助!

SwiftHobby

解决方法

您的findDirection()函数中包含以下代码块:

    let otheryQueue = otherQueue<Pair>()
    let pair = Pair()
    var possibleNeighbours = findPossibleNeighbours(btn: btnArr[playerX][playerY],blockedArr: blockedArr) //returns array of all possible neighbours of given dot
    print(String(possibleNeighbours.description) + " possibeNeighs beginning" )
   //possibleNeighbours.shuffle() //IMPORTANT: Uncomment this to make it more random
    
    for neighbour in possibleNeighbours{
        if(isOnBorder(point: neighbour)){
            print("Blue dot is on border")
            return neighbour
        }
        pair.setPair(firstValue: neighbour,secondValue: neighbour)
        otheryQueue.enqueue(key: pair)
        blockedArr[getXFromString(string: neighbour)][getYFromString(string: neighbour)] = true
    }

    // Start the search
    while(!otheryQueue.isEmpty){
       ...

要调试,我在“开始搜索”之前添加了此代码:

    var p = otheryQueue.first
    while p != nil {
        print("first",p?.data.first,"second",p?.data.second)
        p = p?.next
    }
    
    // Start the search
    while(!otheryQueue.isEmpty){
       ...

如果我先点击任意灰色点(例如0 0),则在控制台中得到的输出为:

Button 0 0 tapped
["4 3","5 4","4 5","3 5","3 4","3 3"] possibeNeighs beginning
first Optional("3 3") second Optional("3 3")
first Optional("3 3") second Optional("3 3")
first Optional("3 3") second Optional("3 3")
first Optional("3 3") second Optional("3 3")
first Optional("3 3") second Optional("3 3")
first Optional("3 3") second Optional("3 3")

(如果我先在3 3上点击,输出将全部为“ 3 4”)。

您的代码仅创建一个pair对象,然后每次通过循环修改其值。

您可能想在每次pair对象时创建一个 .enqueue对象:

    for neighbour in possibleNeighbours{
        if(isOnBorder(point: neighbour)){
            print("Blue dot is on border")
            return neighbour
        }
        
        // add this line
        let pair = Pair()
        
        pair.setPair(firstValue: neighbour,secondValue: neighbour)
        otheryQueue.enqueue(key: pair)
        blockedArr[getXFromString(string: neighbour)][getYFromString(string: neighbour)] = true
    }

现在,当我第一次点击0 0时,我的控制台输出是:

Button 0 0 tapped
["4 3","3 3"] possibeNeighs beginning
first Optional("4 3") second Optional("4 3")
first Optional("5 4") second Optional("5 4")
first Optional("4 5") second Optional("4 5")
first Optional("3 5") second Optional("3 5")
first Optional("3 4") second Optional("3 4")
first Optional("3 3") second Optional("3 3")

您可能想在下一个区块(搜索区块)中做同样的事情:

    // Start the search
    while(!otheryQueue.isEmpty){
        let pointPair = otheryQueue.dequeue()
        let button = btnArr[getXFromString(string: (pointPair?.getFirst())!)][getYFromString(string: (pointPair?.getFirst())!)]
        possibleNeighbours = findPossibleNeighbours(btn: button,blockedArr: blockedArr)
        for neighbour in possibleNeighbours{
            if isOnBorder(point: neighbour){
                return (pointPair?.getSecond())!
            }
            
            // add this line
            let pair = Pair()
            
            pair.setPair(firstValue: neighbour,secondValue: (pointPair?.getSecond())!)
            otheryQueue.enqueue(key: pair)
            blockedArr[getXFromString(string: neighbour)][getYFromString(string: neighbour)] = true
        }
    }