0

So I've built a swift playground that uses Dijkstra's algorithm to find the shortest route. However, I can't seem to manipulate my txt file so that my function will work in every case. It only works for a select few pathways. Whenever I map out a pathway I believe should work, it responds with: Execution was interrupted, reason: EXC_BAD_INSTRUCTION(code=EXC_I386_INVOP, subcode=0x0).

How can I manipulate my txt file or my function/file manipulation to take my txt file input? (Where error occurred is marked -- near the bottom)

Usually the error occurs when trying to build a route backwards.
Ex: a1 to a3 works
Ex: a3 to a1 does not work

Code:

import Foundation

// Extensions

extension Array {
    func each<U>(closure:(Element)->U?)->U? {
        for i in self {
            let returnVal = closure(i)
            if (returnVal != nil) { return returnVal }
        }
        return nil
    }
}

extension Int {
    func times(closure:(Int)->Void) {
        for i in 0..<self { closure(i) }
    }
}

// Structs

struct Edge {
    var wt: Double
    var desV: Room
}

struct Graph { var vertices:[Room] }

// Room Class

class Room: Hashable {

    var name: String?
    var neighbors: [Edge] = []
    var hashValue: Int {
        get { return name!.hashValue }
    }

    init(){}

    convenience init(name:String) {
        self.init()
        self.name = name
    }

    func distanceToRoom(targetRoom:Room) -> Edge? {
        return self.neighbors.each({ (edge:Edge) -> Edge? in
            if (edge.desV == targetRoom) {
                return edge
            }
            return nil
        })
    }
}

// Functions

func == (lhs:Room, rhs:Room) -> Bool { return lhs.hashValue == rhs.hashValue }

func say( a:String ) { print( a, terminator:"") }

func dijkstra(graph:Graph, target:Room) -> [Room:Room] {

    var queue = graph.vertices
    var distances:[Room:Double] = [:]
    var previousPaths:[Room:Room] = [:]
    let currentRoom:Room = queue[0]

    queue.each {(element:Room) -> Void? in
        distances[element] = Double.infinity
        previousPaths[element] = nil
        return nil
    }

    distances[currentRoom] = 0

    while (queue.count > 0) {

        var closestNode:Room? = nil
        let wt:Double = Double.infinity
        queue.each({ (Room:Room) -> Void? in
            if (closestNode == nil || wt < distances[Room]!) {
                closestNode = Room
            }
            return nil
        })
        if (closestNode! == target) {
            return previousPaths
        }

        let nodeIndex:Int? = queue.indexOf(closestNode!)
        queue.removeAtIndex(nodeIndex!)
        if (closestNode?.neighbors != nil && closestNode?.neighbors.count > 0) {
            closestNode?.neighbors.each({(neighbor:Edge) -> Void? in

                let wt = distances[closestNode!]! + closestNode!.distanceToRoom(neighbor.desV)!.wt
                if wt < distances[neighbor.desV] {
                    distances[neighbor.desV] = wt
                    previousPaths[neighbor.desV] = closestNode!
                }
                return nil
            })
        }
    }
    return previousPaths
}

// File Management

//let url = NSURL(string:"file:///Users/caleb/Documents/Xcode/CRHS/CRHS/dtb.txt")!
let url = NSURL(string: "file:///Users/caleb/Desktop/rooms.txt")!
let data = NSData(contentsOfURL: url)
let sdata = String(data: data!, encoding: NSUTF8StringEncoding)
let dataArray = sdata!.characters.split{$0 == "\n"}.map(String.init)
var rooms = [String:Room]()

print("data:\n-------")

for i in 0 ..< dataArray.count {
    let conn = dataArray[i].characters.split{$0 == "\t"}.map(String.init)
    var room1: Room
    if ( rooms[conn[0]] == nil ) {
        room1 = Room(name: conn[0])
    } else {
        room1 = rooms[conn[0]]!
    }

    let room2 = Room(name: conn[2])
    let edwt = (conn[1] as NSString).doubleValue
    var edge = Edge(wt: edwt, desV: room2)

    if room1.neighbors.count == 0 {
        room1.neighbors = [ edge ]
    } else {
        var found: Bool = false
        for e in room1.neighbors {
            if ( e.desV.name == edge.desV.name ) {
                found = true
            }
        }
        if ( found == false ) {
            room1.neighbors.append(edge)
        }
    }
    rooms[conn[0]] = room1
}

for (nam,room) in rooms {
    print(nam)
    print("----")
    for n in room.neighbors {
        if let un = n.desV.name {
            print( un, terminator: "  weight: ")
        }
        print( n.wt )
    }
    print("\n")
}
var namessofrooms = rooms.map { $0.0 }
var roomsofrooms = rooms.map { $0.1 }

print("Rooms:")
print(rooms)
print("-------\n")

// Calculating

var source = rooms["a1"]!
var target = rooms["a4"]!

roomsofrooms.append(source)
var reversedRooms: Array = roomsofrooms.reverse()
reversedRooms.append(target)

var graph = Graph(vertices: reversedRooms)
var paths = dijkstra(graph, target: target)
var pathVertices:[Room] = [target]

var child = target

while (child != source) {
    print(child.name)
    print(":::::")
    child = paths[child]! //Error occurs here
    print(child.name)
    pathVertices.append(child)
}

var pathString:[String] = pathVertices.reverse().map { (Room:Room) -> String in
    return Room.name!
}
print("solution:\n-------")
print(pathString)

Below is the file I input:

a1  1   a2
a2  1   a3
a3  1   a4

If I input the following file the code above will not work:

a1  1   a2
a2  1   a3
a3  1   a4
a4  1   a5

(Update: File Map Clarification) First column is the first room, second is the weight between the rooms, third is the room connected to the first.

Bista
  • 7,869
  • 3
  • 27
  • 55
caleb
  • 391
  • 1
  • 3
  • 11
  • Because of the type and pointer safety inherent in Swift, crashes are usually due to some kind of overrun, like unbounded recursion or a data structure growing until it exceeds process limits. Use debugging statements for growable things like the length of your queue, and my money is on your detecting some unbounded growth. – BaseZen Sep 27 '16 at 17:19
  • Thanks. I'll comment if I find something going through my function. – caleb Sep 27 '16 at 17:29
  • I can't find where my queue is unbounded, it seems to only have a problem near the end when I go through the while loop or something else inside my Dijkstra function. It is limited to the amount of unique values in my first column of rooms. Tested for: (queue.count = 3 in the first file, queue.count = 4 in the second) – caleb Sep 27 '16 at 18:37

0 Answers0