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.