-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathmain.py
executable file
·169 lines (120 loc) · 4.1 KB
/
main.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
#!/usr/bin/python3
import string
import tube
from pprint import pprint
import os
import glob
import collections
def clear_dir(dirname):
files = glob.glob(dirname + "/*")
for f in files:
os.remove(f)
global count
count = 0
def draw_frame():
global count
count += 1
tube_map.output_svg(f"out/frames/{count:05}.svg")
def dijkstra(graph, source, target):
if source not in graph.nodes:
raise ValueError(f"{source} is not a station")
elif target not in graph.nodes:
raise ValueError(f"{target} is not a station")
clear_dir("out/frames")
tube_map.hide_all_stations()
vertices = set(graph.nodes)
dist = collections.defaultdict(lambda: float('inf'))
prev = collections.defaultdict(str)
dist[source] = 0
while vertices:
u = min(vertices, key=lambda x: dist[x])
vertices.remove(u)
tube_map.show_station(u)
draw_frame()
if u == target:
path = []
for station in (set(graph.nodes) - vertices):
tube_map.set_station_opacity(station, 0.25)
tube_map.set_station_opacity(target, 1.0)
draw_frame()
while u in prev:
path.append(u)
u = prev[u]
tube_map.set_station_opacity(u, 1.0)
draw_frame()
tube_map.set_station_opacity(source, 1.0)
for _ in range(10):
draw_frame()
return dist[target], path[::-1]
for v in graph.adj[u]:
if v not in vertices:
continue
alt = dist[u] + graph.edges[u, v]['weight']
if alt < dist[v]:
dist[v] = alt
prev[v] = u
return None, None
def naive(graph, source, target, algo='dfs'):
clear_dir("out/frames")
tube_map.hide_all_stations()
q = collections.deque()
q.append(source)
visited = set()
prev = collections.defaultdict(str)
while len(q) > 0:
if algo == 'bfs':
u = q.popleft()
elif algo == 'dfs':
u = q.pop()
else:
raise NotImplementedError(
f"{algo} search algorithm is not implemented. please try bfs or dfs isntead.")
visited.add(u)
if u == target:
path = []
for station in visited:
tube_map.set_station_opacity(station, 0.25)
tube_map.set_station_opacity(target, 1.0)
draw_frame()
while u in prev:
path.append(u)
u = prev[u]
tube_map.set_station_opacity(u, 1.0)
draw_frame()
tube_map.set_station_opacity(source, 1.0)
for _ in range(10):
draw_frame()
return path[::-1]
for v in graph.adj[u]:
if v in visited or v in q:
continue
q.append(v)
prev[v] = u
tube_map.show_station(v)
draw_frame()
def asciify(s):
return s.translate(string.punctuation)
def draw_shortest_path(station_a, station_b):
route, time = tube_map.compute_shortest_path(
station_a.upper(), station_b.upper())
pprint(route)
print(time)
for station_code in (tube_map.station_names[string.capwords(name)] for name in route[0]):
print(station_code)
tube_map.show_element(tube_map.get_svg_station(station_code))
tube_map.output_svg(f"out/{asciify(station_a)}-{asciify(station_b)}.svg")
def find_longest_shortest_path():
import networkx as nx
lengths = dict(nx.all_pairs_dijkstra(tube_map.graph, weight='weight'))
longest = []
for source in lengths.keys():
furthest = list(lengths[source][0].items())[-1]
longest.append((source, furthest[0], furthest[1]))
return list(sorted(longest, key=lambda x: x[2]))
if __name__ == "__main__":
tube_map = tube.TubeMap()
station_a, station_b = "AMERSHAM", "UPMINSTER"
dist, path = dijkstra(tube_map.as_graph(), station_a, station_b)
pprint(path)
path = naive(tube_map.as_graph(), station_a, station_b, algo='bfs')
pprint(path)