0

I try programming a "Circle the dot" game. Therefor I have to do a Breath First Search over a 2D-Array of UIButtons to find the shortest path from the playerButton to the border.

Unfortunately I sometimes get a Thread 1: Swift runtime failure: force unwrapped a nil value error for several days and I just cannot find the issue.

This is a function of the program to return the next x and y coordinates to move. Thats where I do the BFS.

func findDirection()->String{
    var blocked: [String] = [] 
    let queue = otherQueue<Pair>()
    let pair = Pair()
    var possibleNeighbours = findPossibleNeighbours(btn: btnArr[playerX][playerY], blockedArr: blocked)
    
    for neighbour in possibleNeighbours{
        if(isOnBorder(point: neighbour)){
            return neighbour
        }
        pair.setPair(firstValue: neighbour, secondValue: neighbour)
        queue.enqueue(key: pair)
        blocked.append(neighbour)
    }
    
    //Start the search
    while(!queue.isEmpty){
        let pointPair = queue.dequeue()

        // !!!!!! THIS IS THE ERROR LINE: 
        let button = btnArr[getXFromString(string: (pointPair?.getFirst())!)][getYFromString(string: (pointPair?.getFirst())!)] 
        
        possibleNeighbours = findPossibleNeighbours(btn: button, blockedArr: blocked)
        for neighbour in possibleNeighbours{
            if isOnBorder(point: neighbour){
                return (pointPair?.getSecond())!
            }
            pair.setPair(firstValue: neighbour, secondValue: (pointPair?.getSecond())!)
            queue.enqueue(key: pair)
            blocked.append(neighbour)
        }
    }
    return "-1 -1"
}

The Problem:

It says that pointPair?.getFirst()! is forced unwrapped a nil value. pointPair is the Pair I dequeued from the queue. So my guess was that my queue is empty and tried to dequeue. I checked several times and even wrote a new Queue Class. That was not the problem and the !queue.isEmpty works fine, which is the while-condition. The next guess is that the getFirst(), which returns the first value of my Pair, returns a nil value. This also makes no sense to me as the first value is the iterating neighbour from the possibleNeighbours-Array, which cannot be nil (its only added to the array if it is a POSSIBLE neighbour and obviously exists).

The problem always occurs when the dot has only 2 possible ways to move on. Take this Screenshot as an example.

The blue dot startet at (4, 4). Then I clicked on (2, 3), the dot moved to (3, 3). Then I clicked on (2, 4), the dot moved to (3, 4). Then the button has to possible ways: move to (2, 5) or (3, 5). If you now click on one of both it crashes. In the console I can read that after I clicked on (2, 5) the queue only contained ["3 5"] which is correct as (3, 5) is the only way to move on. Somehow it does not move there and crashes with force unwrapped a nil value...

If you wanna download my whole project and test it you can do so here (hope the link works).

Do you have an idea why it fails? :(

Thanks for any help!

SwiftHobby
  • 67
  • 5

1 Answers1

1

Your problem is in how the dequeue function in otherQueue works. You are adjusting the pointers before returning data, which results in returning nil after removing the head from a queue with one entry.

Try something like...

func dequeue() -> T? {
    if self.head?.data == nil { return nil  }
    let result = head?.data
    if let nextItem = self.head?.next {
        head = nextItem
    } else {
        head = nil
    }
    return result
}

Also, you shouldn't be calling dequeue in while(!otheryQueue.isEmpty || otheryQueue.dequeue() != nil).

Phillip Mills
  • 30,888
  • 4
  • 42
  • 57
  • Awesome Phillip! That was the problem! But for some reason its very strange when you uncomment line 40 (`btnArr[playerX][playerY].backgroundColor = defaultColor`). It should work just like without the line 40 but for some reason I still havent found out why it doesnt. This line just makes all buttons lightgray except the player button (before the player button left "a trail"). – SwiftHobby Oct 12 '20 at 21:28
  • The BFS does not find the shortest path to the border for some reason.... :( Without the neighbours.shuffle() you can often see the dot jumping up and down and up and down, whichout any clue how to get to the border fast – SwiftHobby Oct 12 '20 at 22:06
  • @SwiftHobby The "dot 2" project you sent still has the 2 errors from the earlier version. After fixing those, I don't see a problem, though that may just be that I don't know what it's supposed to do. – Phillip Mills Oct 13 '20 at 14:15
  • Hey @PhillipMills. The basic game idea is that you have to surround the blue dot before it escapes. With every placed obstacle (orange colored dot), the blue dot ("player") moves one step to the border. If you haven't circled the blue dot until he's on the border, you lost and the game restarts. You can see a gameplay here: [link](https://www.youtube.com/watch?v=uAZSPelF41E). – SwiftHobby Oct 13 '20 at 21:27
  • The problem with "dot 2" is that it often doesn't find a path to the border (prints "No path found..." in the console and restarts) EVEN THOUGH there is a possible way for the blue dot to the border/ the dot isn't circled by orange dots. – SwiftHobby Oct 13 '20 at 21:28
  • You may have to play it for some rounds to see what I mean. Against my implementation, it also searches ANY way to the border, not the shortest. Thats why it usually moves pretty random and often even stays in a loop: Up, Down, Up, Down, Up,... which makes it very easy to win. I thought that my BFS searches the shortest path to the border but it looks like it doesn't and I cannot figure out why.. – SwiftHobby Oct 13 '20 at 21:28
  • do you have an idea? – SwiftHobby Oct 14 '20 at 17:36
  • I couldn't see the behavior you describe. Maybe if you give me a set of moves to make that cause it to go wrong, I'd be able to debug it. (The better option might be to ask a new question so that people know that you're no longer looking for a solution to a crash.) – Phillip Mills Oct 14 '20 at 18:13
  • I will do so and send you the link so that. Will be there in some hours – SwiftHobby Oct 14 '20 at 18:17
  • New Stackoverflow Link: [link](https://stackoverflow.com/questions/64375268/breadth-first-search-cant-find-path-shortest-path-to-border-in-2d-array) – SwiftHobby Oct 15 '20 at 15:49
  • I also linked an updated project version and wrote down 3 possible „Button Press Sequences“ where the problem shows up – SwiftHobby Oct 15 '20 at 19:19