github.com/hzck/speedroute@v0.0.0-20201115191102-403b7d0e443f/algorithm/algorithm.go (about) 1 // Package algorithm calculates the shortest path in a directed, weighted graph with a set of requirements. 2 package algorithm 3 4 import ( 5 "container/heap" 6 7 m "github.com/hzck/speedroute/model" 8 ) 9 10 // Route takes a created graph object and finds the shortest path from start to end, returning 11 // that path as a list of edges. 12 func Route(graph *m.Graph) []*m.Edge { 13 if graph.StartNode() == nil || graph.EndNode() == nil { 14 return nil 15 } 16 addMinPathLeft(graph) 17 startPath := m.CreatePath() 18 startPath.AddRewards(graph.StartNode().Rewards()) 19 pq := &m.PrioQueue{} 20 heap.Init(pq) 21 addNodeEdgesToPrioQueue(pq, graph.StartNode(), startPath) 22 for path := prioPath(pq); path != nil; path = prioPath(pq) { 23 node := path.Edges()[len(path.Edges())-1].To() 24 if node == graph.EndNode() { 25 return path.Edges() 26 } 27 addNodeEdgesToPrioQueue(pq, node, path) 28 } 29 return nil 30 } 31 32 func addNodeEdgesToPrioQueue(pq *m.PrioQueue, node *m.Node, path *m.Path) { 33 for _, edge := range node.FromEdges() { 34 ok, i := path.PossibleRoute(edge) 35 if ok { 36 newPath := path.Copy() 37 newPath.AddEdge(edge, i) 38 heap.Push(pq, newPath) 39 } 40 } 41 } 42 43 func prioPath(pq *m.PrioQueue) *m.Path { 44 if pq.Len() > 0 { 45 return heap.Pop(pq).(*m.Path) 46 } 47 return nil 48 } 49 50 func addMinPathLeft(graph *m.Graph) { 51 dp := &m.DijkstraPrio{} 52 heap.Init(dp) 53 visited := make(map[*m.Node]bool) 54 endNode := graph.EndNode() 55 endNode.SetMinPathLeft(0) 56 visited[endNode] = true 57 for _, edge := range endNode.ToEdges() { 58 node := edge.From() 59 node.SetMinPathLeft(edge.FastestTime()) 60 heap.Push(dp, node) 61 } 62 if dp.Len() > 0 { 63 for node := heap.Pop(dp).(*m.Node); dp.Len() > 0; node = heap.Pop(dp).(*m.Node) { 64 visited[node] = true 65 for _, edge := range node.ToEdges() { 66 innerNode := edge.From() 67 if !visited[innerNode] { 68 innerNode.SetMinPathLeft(edge.FastestTime() + node.MinPathLeft()) 69 heap.Push(dp, innerNode) 70 } 71 } 72 } 73 } 74 }