polaris 0.0.1 → 0.0.2

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,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: []