polaris 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,21 @@
1
+ = polaris
2
+
3
+ * http://github.com/shawn42/polaris
4
+
5
+ == DESCRIPTION:
6
+
7
+ A* pathfinding in Ruby. Pulled out of Gamebox.
8
+
9
+
10
+ == REQUIREMENTS:
11
+ * algorithms gem
12
+
13
+ == INSTALL:
14
+
15
+ * gem install poloaris
16
+
17
+ == LICENSE:
18
+
19
+ (MIT)
20
+
21
+ Copyright (c) 2010 Shawn Anderson
@@ -0,0 +1,28 @@
1
+ begin
2
+ require 'jeweler'
3
+ Jeweler::Tasks.new do |gem|
4
+ gem.name = "polaris"
5
+ gem.rubyforge_project = "polaris"
6
+ gem.summary = %Q{A* pathfinding in ruby.}
7
+ gem.description = %Q{A* pathfinding in Ruby, using C datastructures to speed things up.}
8
+ gem.email = "shawn42@gmail.com"
9
+ gem.homepage = "http://github.com/shawn42/polaris"
10
+ gem.authors = ["Shawn Anderson"]
11
+ gem.add_development_dependency "rspec"
12
+ gem.add_development_dependency "jeweler"
13
+ gem.add_dependency 'algorithms'
14
+ gem.test_files = FileList['{spec,test}/**/*.rb']
15
+ end
16
+ Jeweler::GemcutterTasks.new
17
+ rescue LoadError
18
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
19
+ end
20
+
21
+ require 'spec/rake/spectask'
22
+ desc "Run all rspecs"
23
+ Spec::Rake::SpecTask.new(:spec) do |t|
24
+ t.spec_files = FileList['spec/*_spec.rb']
25
+ end
26
+ task :default => :spec
27
+
28
+ # vim: syntax=Ruby
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.2
@@ -0,0 +1,61 @@
1
+ # LineOfSite is a class for finding neighbors in a map that are visible
2
+ class LineOfSite
3
+ def initialize(map)
4
+ @map = map
5
+ end
6
+
7
+ def losline(x, y, x2, y2)
8
+ brensenham_line(x, y, x2, y2).each do |i|
9
+ iterx, itery = *i
10
+ occ = @map.occupant(loc2(iterx,itery))
11
+ return unless occ
12
+ occ.lit = true
13
+ occ.seen = true
14
+
15
+ return if occ.solid?
16
+ end
17
+ end
18
+
19
+ # Brensenham line algorithm
20
+ def brensenham_line(x,y,x2,y2)
21
+ steep = false
22
+ coords = []
23
+ dx = (x2 - x).abs
24
+ if (x2 - x) > 0
25
+ sx = 1
26
+ else
27
+ sx = -1
28
+ end
29
+ dy = (y2 - y).abs
30
+ if (y2 - y) > 0
31
+ sy = 1
32
+ else
33
+ sy = -1
34
+ end
35
+ if dy > dx
36
+ steep = true
37
+ x,y = y,x
38
+ dx,dy = dy,dx
39
+ sx,sy = sy,sx
40
+ end
41
+ d = (2 * dy) - dx
42
+
43
+ dx.times do
44
+ if steep
45
+ coords << [y,x]
46
+ else
47
+ coords << [x,y]
48
+ end
49
+ while d >= 0
50
+ y = y + sy
51
+ d = d - (2 * dx)
52
+ end
53
+ x = x + sx
54
+ d = d + (2 * dy)
55
+ end
56
+ coords << [x2,y2]
57
+
58
+ coords
59
+ end
60
+
61
+ end
@@ -0,0 +1,109 @@
1
+ require 'algorithms'
2
+ include Containers
3
+
4
+ # Polaris is a star that guides, aka "The North Star". It implements the A* algorithm.
5
+ class Polaris
6
+ attr_reader :nodes_considered
7
+
8
+ def initialize(map)
9
+ @map = map
10
+ @nodes_considered = 0
11
+ end
12
+
13
+ # Returns the path without the from location.
14
+ # Returns nil if max_depth is hit or if no path exists.
15
+ def guide(from, to, unit_type=nil, max_depth=400)
16
+ return nil if @map.blocked?(from, unit_type) || @map.blocked?(to, unit_type)
17
+ from_element = PathElement.new(from)
18
+ from_element.dist_from = @map.distance(from,to)
19
+ open = PriorityQueue.new { |x, y| (x <=> y) == -1 }
20
+ open.push from_element, from_element.rating
21
+ closed = SplayTreeMap.new
22
+ step = 0
23
+
24
+ until open.empty? || step > max_depth
25
+ step += 1
26
+
27
+ current_element = open.pop
28
+ @nodes_considered += 1
29
+
30
+ loc = current_element.location
31
+ if @map.cost(loc,to) == 0
32
+ path = []
33
+ until current_element.parent.nil?
34
+ path.unshift current_element
35
+ current_element = current_element.parent
36
+ end
37
+
38
+ return path
39
+ else
40
+ closed.push current_element.location, current_element
41
+ @map.neighbors(loc).each do |next_door|
42
+ el = PathElement.new(next_door,current_element)
43
+ next if closed.has_key? next_door
44
+
45
+ if @map.blocked? next_door, unit_type
46
+ closed.push el.location, el
47
+ else
48
+ current_rating = current_element.cost_to + @map.cost(loc, next_door)
49
+
50
+ # add to open
51
+ el.cost_to = current_rating
52
+ el.dist_from = @map.distance(next_door,to)
53
+
54
+ open.push el, el.rating
55
+ end
56
+ end
57
+ end
58
+ end
59
+ nil
60
+ end
61
+ end
62
+
63
+ class PathElement
64
+ include Comparable
65
+
66
+ attr_accessor :location, :parent
67
+ attr_reader :cost_to, :dist_from, :rating
68
+ def initialize(location=nil,parent=nil)
69
+ @location = location
70
+ @parent = parent
71
+ @cost_to = 0
72
+ @dist_from = 0
73
+ @rating = 99_999
74
+ end
75
+
76
+ def cost_to=(new_cost)
77
+ @cost_to = new_cost
78
+ reset_rating
79
+ end
80
+
81
+ def dist_from=(new_dist_from)
82
+ @dist_from = new_dist_from
83
+ reset_rating
84
+ end
85
+
86
+ def reset_rating
87
+ @rating = @cost_to + @dist_from
88
+ end
89
+
90
+ def to_s
91
+ "#{@location} at cost of #{@cost_to} and rating of #{@rating}"
92
+ end
93
+
94
+ def <=>(b)
95
+ a = self
96
+ if a.rating < b.rating
97
+ return -1
98
+ elsif a.rating > b.rating
99
+ return 1
100
+ else
101
+ 0
102
+ end
103
+ end
104
+
105
+ def ==(other)
106
+ return false if other.nil?
107
+ @location == other.location
108
+ end
109
+ end
@@ -0,0 +1,21 @@
1
+ # TwoDGridLocation exibits an x,y,cost location
2
+ class TwoDGridLocation
3
+ attr_accessor :x,:y
4
+ def initialize(x,y);@x=x;@y=y;end
5
+ def ==(other)
6
+ @x == other.x and @y == other.y
7
+ end
8
+
9
+ def <=>(b)
10
+ ret = 1
11
+ if @x == b.x && @y == b.y
12
+ ret = 0
13
+ end
14
+ ret = -1 if @x <= b.x && @y < b.y
15
+ return ret
16
+ end
17
+
18
+ def to_s
19
+ "#{@x},#{@y}"
20
+ end
21
+ end
@@ -0,0 +1,81 @@
1
+ require 'two_d_grid_location'
2
+
3
+ # TwoDGridMap exibits the contract that the map requires.
4
+ # Works on an X,Y grid that uses Ftors for 2D vectors
5
+ class TwoDGridMap
6
+ attr_accessor :w, :h
7
+ TRAVEL_COST_DIAG = 14
8
+ TRAVEL_COST_STRAIGHT = 10
9
+
10
+ def initialize(w,h)
11
+ @w = w
12
+ @h = h
13
+ @grid = {}
14
+ end
15
+
16
+ def size
17
+ [@w,@h]
18
+ end
19
+
20
+ # place thing at location. If thing is nil, location will be placed in the map
21
+ def place(location, thing=nil)
22
+ thing ||= location
23
+ @grid[location.x] ||= {}
24
+ @grid[location.x][location.y] = thing
25
+ end
26
+
27
+ def occupant(location)
28
+ @grid[location.x][location.y] if @grid[location.x]
29
+ end
30
+
31
+ def clear(location)
32
+ @grid[location.x] ||= {}
33
+ @grid[location.x][location.y] = nil
34
+ end
35
+
36
+ # is the location available for the specified type
37
+ def blocked?(location, type=nil)
38
+ return true if type == :blocked
39
+ return true if location.x >= @w || location.y >= @h || location.x < 0 || location.y < 0
40
+ if @grid[location.x] and @grid[location.x][location.y]
41
+ return true
42
+ else
43
+ return false
44
+ end
45
+ end
46
+
47
+ # returns a list of neighbors and their distance
48
+ def neighbors(location)
49
+ x = location.x
50
+ y = location.y
51
+ [
52
+ TwoDGridLocation.new(x-1, y-1),
53
+ TwoDGridLocation.new(x-1, y+1),
54
+ TwoDGridLocation.new(x+1, y-1),
55
+ TwoDGridLocation.new(x+1, y+1),
56
+ TwoDGridLocation.new(x-1, y),
57
+ TwoDGridLocation.new(x+1, y),
58
+ TwoDGridLocation.new(x, y-1),
59
+ TwoDGridLocation.new(x, y+1)
60
+ ]
61
+ end
62
+
63
+ def distance(from,to)
64
+ h_diagonal = [(from.x-to.x).abs, (from.y-to.y).abs].min
65
+ h_straight = ((from.x-to.x).abs + (from.y-to.y).abs)
66
+ return TRAVEL_COST_DIAG * h_diagonal + TRAVEL_COST_STRAIGHT * (h_straight - 2*h_diagonal)
67
+ end
68
+
69
+ # return the cost to go from => to (assuming from and to are neighbors)
70
+ def cost(from, to)
71
+ if from.x == to.x or from.y == to.y
72
+ if from.x == to.x and from.y == to.y
73
+ 0
74
+ else
75
+ TRAVEL_COST_STRAIGHT
76
+ end
77
+ else
78
+ TRAVEL_COST_DIAG
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,62 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{polaris}
8
+ s.version = "0.0.2"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Shawn Anderson"]
12
+ s.date = %q{2010-02-27}
13
+ s.description = %q{A* pathfinding in Ruby, using C datastructures to speed things up.}
14
+ s.email = %q{shawn42@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "README.txt"
17
+ ]
18
+ s.files = [
19
+ "README.txt",
20
+ "Rakefile",
21
+ "VERSION",
22
+ "lib/line_of_site.rb",
23
+ "lib/polaris.rb",
24
+ "lib/two_d_grid_location.rb",
25
+ "lib/two_d_grid_map.rb",
26
+ "polaris.gemspec",
27
+ "spec/helper.rb",
28
+ "spec/line_of_site_spec.rb",
29
+ "spec/polaris_spec.rb"
30
+ ]
31
+ s.homepage = %q{http://github.com/shawn42/polaris}
32
+ s.rdoc_options = ["--charset=UTF-8"]
33
+ s.require_paths = ["lib"]
34
+ s.rubyforge_project = %q{polaris}
35
+ s.rubygems_version = %q{1.3.6}
36
+ s.summary = %q{A* pathfinding in ruby.}
37
+ s.test_files = [
38
+ "spec/helper.rb",
39
+ "spec/line_of_site_spec.rb",
40
+ "spec/polaris_spec.rb"
41
+ ]
42
+
43
+ if s.respond_to? :specification_version then
44
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
45
+ s.specification_version = 3
46
+
47
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
48
+ s.add_development_dependency(%q<rspec>, [">= 0"])
49
+ s.add_development_dependency(%q<jeweler>, [">= 0"])
50
+ s.add_runtime_dependency(%q<algorithms>, [">= 0"])
51
+ else
52
+ s.add_dependency(%q<rspec>, [">= 0"])
53
+ s.add_dependency(%q<jeweler>, [">= 0"])
54
+ s.add_dependency(%q<algorithms>, [">= 0"])
55
+ end
56
+ else
57
+ s.add_dependency(%q<rspec>, [">= 0"])
58
+ s.add_dependency(%q<jeweler>, [">= 0"])
59
+ s.add_dependency(%q<algorithms>, [">= 0"])
60
+ end
61
+ end
62
+
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 0
8
- - 1
9
- version: 0.0.1
8
+ - 2
9
+ version: 0.0.2
10
10
  platform: ruby
11
11
  authors:
12
12
  - Shawn Anderson
@@ -59,10 +59,20 @@ executables: []
59
59
 
60
60
  extensions: []
61
61
 
62
- extra_rdoc_files: []
63
-
64
- files: []
65
-
62
+ extra_rdoc_files:
63
+ - README.txt
64
+ files:
65
+ - README.txt
66
+ - Rakefile
67
+ - VERSION
68
+ - lib/line_of_site.rb
69
+ - lib/polaris.rb
70
+ - lib/two_d_grid_location.rb
71
+ - lib/two_d_grid_map.rb
72
+ - polaris.gemspec
73
+ - spec/helper.rb
74
+ - spec/line_of_site_spec.rb
75
+ - spec/polaris_spec.rb
66
76
  has_rdoc: true
67
77
  homepage: http://github.com/shawn42/polaris
68
78
  licenses: []