etapeta (owner)

Revisions

gist: 71535 Download_button fork
public
Public Clone URL: git://gist.github.com/71535.git
Embed All Files: show embed
Transitive_search_in_arbitrary_graph.rb #
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
# Object::transitive_detect
# Transitive closure search of a (directed, eventually cyclic) graph.
# No requirement on graph implementation.
 
class Object
 
  # transitive closure visit
  # the required block gets passed an object and it returns:
  # - nil (or false, or []), if the object certainly does not match the condition
  # - the object itself, if the object matches the condition
  # - an array of delegates objects, if the condition match depends on one of them
  # Note: a simple variant of this method could return the path followed.
  def transitive_detect(&block)
    return nil unless self
    to_visit = self.is_a?(Array) ? self : [self]
    visited = []
    until to_visit.empty?
      obj = to_visit.pop
      result = block.call(obj)
      return result if result && !result.is_a?(Array)
      visited << obj
      result.each do |res|
        to_visit << res unless visited.include?(res)
      end if result
    end
    nil
  end
 
end
 
air_routes = {
  :rome => [:london, :amsterdam],
  :london => [:new_york, :paris],
  :paris => [:oslo, :rome, :london],
  :new_york => [:boston, :los_angeles],
  :boston => [:new_york],
  :los_angeles => [:new_york, :san_francisco],
  :miami => [:new_orleans],
  :new_orleans => [:miami],
}
 
def air_route_from_to(city1, city2, routes)
  found = city1.transitive_detect {|city| (city == city2) ? city : routes[city] }
  puts "From #{city1} to #{city2}: #{found ? 'Y': 'N'}"
end
 
cities = [:rome, :miami, :boston, :oslo, :new_orleans, :los_angeles]
cities.each do |c1|
  cities.each do |c2|
    air_route_from_to(c1, c2, air_routes)
  end
end