maneuver 0.0.1pre

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,2 @@
1
+ %w(maneuver node edge graph cost_algorithm
2
+ search_algorithm first_search a_star).each { |f| require "maneuver/#{f}" }
@@ -0,0 +1,56 @@
1
+ require 'maneuver/search_algorithm'
2
+
3
+ module Maneuver
4
+ class AStar < SearchAlgorithm
5
+ def self.path(from, to, cost_algorithm)
6
+ raise "EdgeAlgorithm hueristic (param #3 => cost_algorithm) can not be nil" unless cost_algorithm
7
+ open = [from]
8
+ estimate = Maneuver.cost_algorithms[cost_algorithm]
9
+ came_from = {}
10
+ g_score = { from => 0}
11
+ f_score = { from => g_score[from] + estimate.compute(from, to)}
12
+
13
+ while !open.empty?
14
+ current = self.key_with_min_value open, f_score
15
+ return reconstruct_path(came_from, to) if current == to
16
+ open.delete current
17
+ current.outgoing_edges.each do |e|
18
+ n = e.to
19
+ t_g_score = g_score[current] + e.cost(cost_algorithm)
20
+ if !open.include? n || t_g_score <= g_score[n]
21
+ came_from[n] = current
22
+ g_score[n] = t_g_score
23
+ f_score[n] = t_g_score + estimate.compute(n, to)
24
+ open << n unless open.include? n
25
+ end
26
+ end
27
+ end
28
+ nil
29
+ end
30
+
31
+ def self.key_with_min_value(set, hash)
32
+ min_value = Float::MAX
33
+ min_key = nil
34
+ set.each do |k|
35
+ m = hash[k]
36
+ if m < min_value
37
+ min_key = k
38
+ min_value = m
39
+ end
40
+ end
41
+ min_key
42
+ end
43
+
44
+ def self.reconstruct_path(came_from, current)
45
+ path = [current]
46
+ while came_from.key? current
47
+ n = came_from[current]
48
+ path.unshift n
49
+ current = n
50
+ end
51
+ path
52
+ end
53
+ end
54
+
55
+ add_search_algorithm :a_star, AStar
56
+ end
@@ -0,0 +1,29 @@
1
+ module Maneuver
2
+ class CostAlgorithm
3
+ class << self
4
+ attr_accessor :cache
5
+
6
+ def compute(from, to)
7
+ 0
8
+ end
9
+
10
+ def method_added(method)
11
+ return unless method.to_sym == :compute
12
+ self.send :define_singleton_method, :_sing_compute, self.method(method.to_sym)
13
+ self.singleton_method_added(:_sing_compute)
14
+ end
15
+
16
+ def singleton_method_added(method)
17
+ return if method.to_sym != :compute &&
18
+ method.to_sym != :_sing_compute
19
+ internal = lambda do |from, to|
20
+ self.cache ||= {}
21
+ self.cache[[from, to]] ||= begin
22
+ self.send :compute, from, to
23
+ end
24
+ end
25
+ self.send :define_singleton_method, :_compute, internal
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,17 @@
1
+ module Maneuver
2
+ class Edge
3
+ attr_reader :from, :to
4
+
5
+ def initialize(from, to)
6
+ @from, @to = from, to
7
+ from.edges << self
8
+ to.edges << self
9
+ end
10
+
11
+ def cost(algorithm)
12
+ ca = Maneuver.cost_algorithms[algorithm]
13
+ raise "Unknow Cost Algorithm: #{algorithm}" unless ca
14
+ ca._compute(@from, @to)
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,66 @@
1
+ require 'maneuver/search_algorithm'
2
+
3
+ module Maneuver
4
+
5
+ class FirstSearch < SearchAlgorithm
6
+ def self.prep_node
7
+ Maneuver::Node.send :define_method, :_fs_parent, lambda { instance_variable_get :@_fs_parent }
8
+ Maneuver::Node.send :define_method, :_fs_parent=, lambda {|a| instance_variable_set(:@_fs_parent, a)}
9
+ end
10
+
11
+ def self.clean_node
12
+ Maneuver::Node.send :remove_method, :_fs_parent
13
+ Maneuver::Node.send :remove_method, :_fs_parent=
14
+ end
15
+
16
+ def self.reconstruct_path(node)
17
+ path = [node]
18
+ while node._fs_parent
19
+ path.unshift node._fs_parent
20
+ node = node._fs_parent
21
+ end
22
+ self.clean_node
23
+ path
24
+ end
25
+
26
+ def self.get_node(nodes_to_check)
27
+ nil
28
+ end
29
+
30
+ def self.path(from, to, edge_algorithm = nil)
31
+ return from if from == to
32
+ self.prep_node
33
+ nodes_to_check = []
34
+ visited = [from]
35
+ from.outgoing_edges.each { |edge| edge.to._fs_parent = from; nodes_to_check << edge.to }
36
+ while !nodes_to_check.empty?
37
+ node = self.get_node nodes_to_check
38
+ return self.reconstruct_path(to) if node == to
39
+ node.outgoing_edges.each do |e|
40
+ test = e.to
41
+ unless visited.include? test
42
+ test._fs_parent = node
43
+ visited << test
44
+ nodes_to_check.unshift test
45
+ end
46
+ end
47
+ end
48
+ self.clean_node
49
+ nil
50
+ end
51
+ end
52
+
53
+ class DFS < FirstSearch
54
+ def self.get_node(nodes_to_check)
55
+ nodes_to_check.shift
56
+ end
57
+ end
58
+
59
+ class BFS < FirstSearch
60
+ def self.get_node(nodes_to_check)
61
+ nodes_to_check.pop
62
+ end
63
+ end
64
+
65
+ [[:bfs, BFS], [:dfs, DFS]].each { |alg| add_search_algorithm alg[0], alg[1]}
66
+ end
@@ -0,0 +1,39 @@
1
+ module Maneuver
2
+ class Graph
3
+ def initialize(edges = [])
4
+ @nodes = []
5
+ @edges = edges.map { |e| Edge.new e[0], e[1] }
6
+ @edges.each do |e|
7
+ @nodes << e.to unless @nodes.include? e.to
8
+ @nodes << e.from unless @nodes.include? e.from
9
+ end
10
+ end
11
+
12
+ def insert_nodes(*nodes)
13
+ nodes.each { |n| @nodes << n unless @nodes.include? n }
14
+ end
15
+
16
+ def insert_edges(*edges)
17
+ edges.each do |e|
18
+ unless has_edge e
19
+ @edges << e
20
+ @nodes << e.to unless @nodes.include? e.to
21
+ @nodes << e.from unless @nodes.include? e.from
22
+ end
23
+ end
24
+ end
25
+
26
+ def has_edge(edge)
27
+ exists = false
28
+ @edges.each { |e| break if (exists = (e.from == edge.from &&
29
+ e.to == edge.to)) }
30
+ exists
31
+ end
32
+
33
+ def path(from, to, search_algorithm, cost_algorithm = nil)
34
+ search = Maneuver.search_algorithms[search_algorithm]
35
+ raise "Unknown Search Algorithm: #{search_algorithm}" unless search
36
+ search.path(from, to, cost_algorithm)
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,23 @@
1
+ module Maneuver
2
+ @@cost_algorithms = {}
3
+ @@search_algorithms = {}
4
+
5
+ class << self
6
+ def add_cost_algorithm(sym, klass)
7
+ @@cost_algorithms[sym] = klass
8
+ end
9
+
10
+ def cost_algorithms
11
+ @@cost_algorithms
12
+ end
13
+
14
+ def add_search_algorithm(sym, klass)
15
+ @@search_algorithms[sym] = klass
16
+ end
17
+
18
+ def search_algorithms
19
+ @@search_algorithms
20
+ end
21
+ end
22
+
23
+ end
@@ -0,0 +1,24 @@
1
+ module Maneuver
2
+ class Node
3
+ attr_reader :edges
4
+ def initialize(*args)
5
+ @edges = []
6
+ end
7
+
8
+ def outgoing_edges
9
+ @edges.reject { |e| e.to == self }
10
+ end
11
+
12
+ def incoming_edges
13
+ @edges.reject { |e| e.from == self }
14
+ end
15
+
16
+ def out_degree
17
+ outgoing_edges.length
18
+ end
19
+
20
+ def in_degree
21
+ incoming_edges.length
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,7 @@
1
+ module Maneuver
2
+ class SearchAlgorithm
3
+ def self.path(from, to, cost_algorithm = nil)
4
+ nil
5
+ end
6
+ end
7
+ end
metadata ADDED
@@ -0,0 +1,53 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: maneuver
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1pre
5
+ prerelease: 5
6
+ platform: ruby
7
+ authors:
8
+ - Kayle Gishen
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-11-19 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: A simple graph library with path planning.
15
+ email: kayle@moremagic.io
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - lib/maneuver/a_star.rb
21
+ - lib/maneuver/cost_algorithm.rb
22
+ - lib/maneuver/edge.rb
23
+ - lib/maneuver/first_search.rb
24
+ - lib/maneuver/graph.rb
25
+ - lib/maneuver/maneuver.rb
26
+ - lib/maneuver/node.rb
27
+ - lib/maneuver/search_algorithm.rb
28
+ - lib/maneuver.rb
29
+ homepage: https://github.com/kayleg/maneuver
30
+ licenses: []
31
+ post_install_message:
32
+ rdoc_options: []
33
+ require_paths:
34
+ - lib
35
+ required_ruby_version: !ruby/object:Gem::Requirement
36
+ none: false
37
+ requirements:
38
+ - - ! '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ required_rubygems_version: !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ! '>'
45
+ - !ruby/object:Gem::Version
46
+ version: 1.3.1
47
+ requirements: []
48
+ rubyforge_project:
49
+ rubygems_version: 1.8.24
50
+ signing_key:
51
+ specification_version: 3
52
+ summary: Graph and Path Planning
53
+ test_files: []