main
1#!/usr/bin/env ruby
2
3require 'set'
4
5def assert_equal(expected, actual)
6 raise [expected, actual].inspect unless expected == actual
7end
8
9def assert_includes(expected, actual)
10 puts [expected, 'not found in', actual].inspect unless actual.include?(expected)
11end
12
13class Graph
14 def initialize
15 @graph = Hash.new { |h, k| h[k] = Set.new }
16 end
17
18 def connect(source, destination, _distance)
19 @graph[source] << destination
20 @graph[destination] << source
21 end
22
23 def paths_between(source, destination)
24 visited = Hash.new { |h, k| h[k] = false }
25 [].tap do |paths|
26 traverse(source, destination, visited) do |found|
27 paths.push(found.dup)
28 end
29 end
30 end
31
32 def inspect
33 @graph.inspect
34 end
35
36 private
37
38 def traverse(source, destination, visited, path = [])
39 visited[source] = true
40 path << source
41
42 if source == destination
43 yield path
44 else
45 @graph[source].each do |i|
46 if visited[i] == false
47 traverse(i, destination, visited, path) do |path|
48 yield path
49 end
50 end
51 end
52 end
53
54 path.pop
55 visited[source] = false
56 end
57end
58
59graph = Graph.new
60graph.connect(:a, :b, 5)
61graph.connect(:a, :d, 6)
62graph.connect(:a, :f, 3)
63graph.connect(:b, :c, 4)
64graph.connect(:b, :e, 2)
65graph.connect(:c, :d, 3)
66graph.connect(:c, :e, 1)
67graph.connect(:c, :g, 2)
68graph.connect(:d, :e, 1)
69graph.connect(:f, :g, 8)
70puts graph.inspect
71
72puts ""
73puts "Paths from A to G"
74results = graph.paths_between(:a, :g)
75results.each do |result|
76 puts result.inspect
77end
78assert_includes([:a,:b,:c,:g], results)
79assert_includes([:a,:b,:e,:c,:g], results)
80assert_includes([:a,:b,:e,:d,:c,:g], results)
81assert_includes([:a,:d,:c,:g], results)
82assert_includes([:a,:d,:e,:b,:c,:g], results)
83assert_includes([:a,:d,:e,:c,:g], results)
84assert_includes([:a,:f,:g], results)
85assert_equal([
86 [:a,:b,:c,:g],
87 [:a,:b,:e,:c,:g],
88 [:a,:b,:e,:d,:c,:g],
89 [:a,:d,:c,:g],
90 [:a,:d,:e,:b,:c,:g],
91 [:a,:d,:e,:c,:g],
92 [:a,:f,:g]
93], results)
94
95puts "Without E"
96graph = Graph.new
97graph.connect(:a, :b, 5)
98graph.connect(:a, :d, 6)
99graph.connect(:a, :f, 3)
100graph.connect(:b, :c, 4)
101graph.connect(:c, :d, 3)
102graph.connect(:c, :g, 2)
103graph.connect(:f, :g, 8)
104puts graph.inspect
105results = graph.paths_between(:a, :g)
106results.each do |result|
107 puts result.inspect
108end
109assert_equal([
110 [:a,:b,:c,:g],
111 [:a,:d,:c,:g],
112 [:a,:f,:g]
113], results)