castar 0.0.1
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.
- data/.gitignore +4 -0
- data/Gemfile +5 -0
- data/README.markdown +106 -0
- data/Rakefile +1 -0
- data/benchmarks/benchmark_helper.rb +163 -0
- data/benchmarks/benchmarker.rb +35 -0
- data/benchmarks/example.rb +37 -0
- data/benchmarks/map90.0.txt +90 -0
- data/benchmarks/map90.1.txt +90 -0
- data/castar.gemspec +26 -0
- data/ext/extconf.rb +3 -0
- data/ext/findpath.h +498 -0
- data/ext/fsa.h +250 -0
- data/ext/heyes_wrap.cxx +3641 -0
- data/ext/stlastar.h +755 -0
- data/lib/castar.rb +78 -0
- data/lib/castar/version.rb +3 -0
- data/spec/castar_spec.rb +107 -0
- data/spec/map_20.txt +20 -0
- data/swig/buildRubyExtension.sh +4 -0
- data/swig/heyes.i +7 -0
- metadata +127 -0
data/lib/castar.rb
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
require "castar/version"
|
2
|
+
|
3
|
+
module Castar
|
4
|
+
require 'heyes' # the .bundle file
|
5
|
+
include Heyes # so we don't have to specify Castar::Heyes:: ...
|
6
|
+
|
7
|
+
|
8
|
+
#convenience functions
|
9
|
+
module_function #make all the following instance methods module methods
|
10
|
+
|
11
|
+
def init_map( options={} )
|
12
|
+
defaults = {:width => 90, :height => 90}
|
13
|
+
options = defaults.merge(options)
|
14
|
+
nrow = options[:height]
|
15
|
+
ncol = options[:width]
|
16
|
+
|
17
|
+
# set cost for each cell to 1
|
18
|
+
a = Array.new(nrow).fill( Array.new(ncol).fill(1) )
|
19
|
+
map = Map.new(ncol, nrow)
|
20
|
+
a.each_with_index do |row, y|
|
21
|
+
row.each_with_index do |cost, x|
|
22
|
+
map.setCost(x,y,cost)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
return map
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
def load_map(mapfile)
|
31
|
+
map = nil
|
32
|
+
y = 0
|
33
|
+
File.open(mapfile) do |f|
|
34
|
+
f.each_line do |line|
|
35
|
+
entries = line.chomp.split(',')
|
36
|
+
map ||= Castar::Map.new( entries.size, entries.size )
|
37
|
+
x = 0
|
38
|
+
line.chomp.split(',').each do |cost|
|
39
|
+
map.setCost(x,y,cost.to_i)
|
40
|
+
x += 1
|
41
|
+
end
|
42
|
+
y += 1
|
43
|
+
end
|
44
|
+
end
|
45
|
+
return map
|
46
|
+
end
|
47
|
+
|
48
|
+
def get_path(driver)
|
49
|
+
path = [];
|
50
|
+
(0..driver.getPathLength-1).each do |i|
|
51
|
+
path << {:x => driver.getPathXAtIndex(i), :y => driver.getPathYAtIndex(i)}
|
52
|
+
end
|
53
|
+
path
|
54
|
+
end
|
55
|
+
|
56
|
+
def get_map_with_path(driver)
|
57
|
+
path = get_path(driver)
|
58
|
+
pathstr="\n"
|
59
|
+
map = driver.getMap
|
60
|
+
(0..map.height-1).each do |row|
|
61
|
+
(0..map.width-1).each do |col|
|
62
|
+
value = map.getCost(col,row)
|
63
|
+
if(row==driver.nodeStart.y and col==driver.nodeStart.x)
|
64
|
+
pathstr<<"|S"
|
65
|
+
elsif(row==driver.nodeEnd.y and col==driver.nodeEnd.x)
|
66
|
+
pathstr<<"|G"
|
67
|
+
elsif(path.include?(:x => col, :y => row) )
|
68
|
+
pathstr<<"|*"
|
69
|
+
else
|
70
|
+
pathstr<<"|#{value}"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
pathstr<<"|\n"
|
74
|
+
end
|
75
|
+
return pathstr
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
data/spec/castar_spec.rb
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
$: << File.join(File.expand_path(File.dirname(__FILE__)), '..')
|
2
|
+
require "castar"
|
3
|
+
include Castar
|
4
|
+
|
5
|
+
describe "astar pathfinding wrapper" do
|
6
|
+
it "should load a map" do
|
7
|
+
num_column = 4
|
8
|
+
num_row = 2
|
9
|
+
map = init_map(:width => num_column, :height => num_row)
|
10
|
+
map.height.should eq(num_row)
|
11
|
+
map.width.should eq(num_column)
|
12
|
+
|
13
|
+
(0..num_column-1).each do |x|
|
14
|
+
(0..num_row-1).each do |y|
|
15
|
+
num = rand(10)
|
16
|
+
map.setCost(x,y,num)
|
17
|
+
map.getCost(x,y).should eq(num)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
map.getCost(4,1).should eq(Map::MAP_OUT_OF_BOUNDS)
|
22
|
+
map.getCost(1,2).should eq(Map::MAP_OUT_OF_BOUNDS)
|
23
|
+
map.getCost(10,10).should eq(Map::MAP_OUT_OF_BOUNDS)
|
24
|
+
end
|
25
|
+
it "map saved in driver should work" do
|
26
|
+
num_column = 4
|
27
|
+
num_row = 2
|
28
|
+
map1 = Map.new(num_column, num_row)
|
29
|
+
driver = HeyesDriver.new(map1)
|
30
|
+
map = driver.getMap
|
31
|
+
map.height.should eq(num_row)
|
32
|
+
map.width.should eq(num_column)
|
33
|
+
|
34
|
+
(0..num_column-1).each do |x|
|
35
|
+
(0..num_row-1).each do |y|
|
36
|
+
num = rand(10)
|
37
|
+
map.setCost(x,y,num)
|
38
|
+
map.getCost(x,y).should eq(num)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
map.getCost(4,1).should eq(Map::MAP_OUT_OF_BOUNDS)
|
43
|
+
map.getCost(1,2).should eq(Map::MAP_OUT_OF_BOUNDS)
|
44
|
+
map.getCost(10,10).should eq(Map::MAP_OUT_OF_BOUNDS)
|
45
|
+
end
|
46
|
+
|
47
|
+
before :each do
|
48
|
+
@map = init_map(:width => 4, :height => 2)
|
49
|
+
@startx = 0
|
50
|
+
@starty = 0
|
51
|
+
@goalx = 3
|
52
|
+
@goaly = 0
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should allow access to start and goal nodes" do
|
56
|
+
driver = HeyesDriver.new(@map)
|
57
|
+
driver.run(@startx, @starty, @goalx, @goaly)
|
58
|
+
driver.nodeStart.x.should eq @startx
|
59
|
+
driver.nodeStart.y.should eq @starty
|
60
|
+
driver.nodeEnd.x.should eq @goalx
|
61
|
+
driver.nodeEnd.y.should eq @goaly
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should find a path when start and goal are the same" do
|
65
|
+
driver = HeyesDriver.new(@map)
|
66
|
+
driver.run(@startx, @starty, @startx, @starty)
|
67
|
+
path = get_path(driver)
|
68
|
+
path.length.should eq(1)
|
69
|
+
path.first.should eq({:x => 0, :y => 0})
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should find the shortest path (no obstacle) " do
|
73
|
+
driver = HeyesDriver.new(@map)
|
74
|
+
driver.run(@startx, @starty, @goalx, @goaly)
|
75
|
+
path = get_path(driver)
|
76
|
+
path.length.should eq(4)
|
77
|
+
path.should eq([ {:x => 0, :y => 0}, {:x => 1, :y => 0}, {:x => 2, :y => 0}, {:x => 3, :y => 0}])
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should find the shortest path allowing diagonal moves(no obstacle) " do
|
81
|
+
driver = HeyesDriver.new(@map, HeyesDriver::EIGHT_NEIGHBORS)
|
82
|
+
@starty=1
|
83
|
+
driver.run(@startx, @starty, @goalx, @goaly)
|
84
|
+
path = get_path(driver)
|
85
|
+
path.length.should eq(4)
|
86
|
+
#path.should eq([ {:x => 0, :y => 0}, {:x => 1, :y => 0}, {:x => 2, :y => 0}, {:x => 3, :y => 0}])
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should find the shortest path (obstacle) " do
|
90
|
+
@map.setCost(1,0,Map::MAP_NO_WALK)
|
91
|
+
driver = HeyesDriver.new(@map)
|
92
|
+
driver.run(@startx, @starty, @goalx, @goaly)
|
93
|
+
path = get_path(driver)
|
94
|
+
path.length.should eq(6)
|
95
|
+
end
|
96
|
+
|
97
|
+
it "should load mapfile and find path" do
|
98
|
+
map =load_map('./spec/map_20.txt')
|
99
|
+
astar = HeyesDriver.new(map, HeyesDriver::EIGHT_NEIGHBORS)
|
100
|
+
astar.run(0,0,19,19)
|
101
|
+
astar.getPathLength.should eq 28
|
102
|
+
end
|
103
|
+
|
104
|
+
it "should have tests for memory management"
|
105
|
+
|
106
|
+
end
|
107
|
+
|
data/spec/map_20.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
|
2
|
+
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
|
3
|
+
1,1,9,9,9,9,1,1,1,1,1,9,9,9,9,9,9,9,9,9
|
4
|
+
1,1,9,9,9,9,1,1,1,1,1,9,9,9,9,9,9,9,9,9
|
5
|
+
1,1,9,9,9,9,1,1,1,1,1,9,9,9,9,9,9,9,9,9
|
6
|
+
1,1,9,9,9,9,1,1,1,1,1,9,9,9,9,9,9,9,9,9
|
7
|
+
1,1,9,9,9,9,1,1,1,1,1,9,9,9,9,9,9,9,9,9
|
8
|
+
1,1,9,9,9,9,1,1,1,1,1,9,9,9,9,9,9,9,9,9
|
9
|
+
1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,9,9,9,9,9
|
10
|
+
1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,9,9,9,9,9
|
11
|
+
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
|
12
|
+
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
|
13
|
+
1,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,1,1,1
|
14
|
+
1,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,1,1,1
|
15
|
+
1,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,1,1,1
|
16
|
+
1,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,1,1,1
|
17
|
+
1,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,1,1,1
|
18
|
+
1,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,1,1,1
|
19
|
+
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
|
20
|
+
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
|
data/swig/heyes.i
ADDED
metadata
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: castar
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- John Wilde
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-12-15 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rspec
|
16
|
+
requirement: &2156210560 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *2156210560
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: rspec-core
|
27
|
+
requirement: &2156208020 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *2156208020
|
36
|
+
description: ! "## DESCRIPTION:\n\nRuby interface to a C++ implemention of the A\\*
|
37
|
+
search algorithm.\n\nThe C++ implementaion is found here <http://code.google.com/p/a-star-algorithm-implementation/>\n\n\n##
|
38
|
+
FEATURES:\n\n\n## SYNOPSIS:\n\nSee `spec\\castar_spec.rb` for usage examples.\n\nCreate
|
39
|
+
an empty map and plan a path across it:\n\n require 'castar'\n include
|
40
|
+
Castar\n map = init_map(:width => 4, :height => 3)\n astar = HeyesDriver.new(map,
|
41
|
+
HeyesDriver::EIGHT_NEIGHBORS)\n astar.run(0,0,3,2)\n puts get_map_with_path(astar)\n\n
|
42
|
+
\ |S|1|1|1|\n |1|*|1|1|\n |1|1|*|G|\n \n\nLoad a map
|
43
|
+
from a text file and plan a path:\n\n map = load_map('./spec/map_20.txt')\n
|
44
|
+
\ astar = HeyesDriver.new(map, HeyesDriver::EIGHT_NEIGHBORS)\n astar.run(0,0,19,19)\n
|
45
|
+
\ puts get_map_with_path(astar)\n\n \n |S|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|\n
|
46
|
+
\ |1|*|*|*|*|*|1|1|1|1|1|1|1|1|1|1|1|1|1|1|\n |1|1|9|9|9|9|*|1|1|1|1|9|9|9|9|9|9|9|9|9|\n
|
47
|
+
\ |1|1|9|9|9|9|1|*|1|1|1|9|9|9|9|9|9|9|9|9|\n |1|1|9|9|9|9|1|1|*|1|1|9|9|9|9|9|9|9|9|9|\n
|
48
|
+
\ |1|1|9|9|9|9|1|1|1|*|1|9|9|9|9|9|9|9|9|9|\n |1|1|9|9|9|9|1|1|1|1|*|9|9|9|9|9|9|9|9|9|\n
|
49
|
+
\ |1|1|9|9|9|9|1|1|1|1|*|9|9|9|9|9|9|9|9|9|\n |1|1|1|1|1|1|1|1|1|1|*|9|9|9|9|9|9|9|9|9|\n
|
50
|
+
\ |1|1|1|1|1|1|1|1|1|1|*|9|9|9|9|9|9|9|9|9|\n |1|1|1|1|1|1|1|1|1|1|1|*|1|1|1|1|1|1|1|1|\n
|
51
|
+
\ |1|1|1|1|1|1|1|1|1|1|1|1|*|*|*|*|*|1|1|1|\n |1|1|1|1|1|9|9|9|9|9|9|9|9|9|9|9|9|*|1|1|\n
|
52
|
+
\ |1|1|1|1|1|9|9|9|9|9|9|9|9|9|9|9|9|1|*|1|\n |1|1|1|1|1|9|9|9|9|9|9|9|9|9|9|9|9|1|1|*|\n
|
53
|
+
\ |1|1|1|1|1|9|9|9|9|9|9|9|9|9|9|9|9|1|1|*|\n |1|1|1|1|1|9|9|9|9|9|9|9|9|9|9|9|9|1|1|*|\n
|
54
|
+
\ |1|1|1|1|1|9|9|9|9|9|9|9|9|9|9|9|9|1|1|*|\n |1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|*|\n
|
55
|
+
\ |1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|G|\n \n## REQUIREMENTS:\n\n*
|
56
|
+
Ruby 1.9 \n* C compiler for C extensions \n\n## DEVELOPMENT\n\nTo modify the gem
|
57
|
+
in a cloned repo this is what I'm doing (from root of gem):\n\n bundle install\n
|
58
|
+
\ cd ext/\n ruby extconf.rb\n make \n\nThese steps will install
|
59
|
+
the development dependencies, build the Makefile and compile the C++ code. Running\n\n
|
60
|
+
\ bundle exec rspec ./spec\n\nshould show all tests passing. To clean up the
|
61
|
+
autogenerated Makefile and the compiled objects:\n\n cd ext/\n make
|
62
|
+
realclean\n\nIf you need to regenerate the ruby interface functions `heyes_wrap.cxx`,
|
63
|
+
run:\n\n cd swig/\n swig -c++ -ruby heyes.i\n mv heyes_wrap.cxx
|
64
|
+
../ext\n\nIf you are just trying to run the tests:\n\n rake build\n gem
|
65
|
+
install pkg/castar-0.0.1.gem\n\nbuilds the gem and installs it to your local machine.\n\n
|
66
|
+
\ gem which castar\n\ntells you where it is. You can then cd to that directory
|
67
|
+
and run the tests as above (but since you're not in a git repo you can't commit
|
68
|
+
them).\n\nI followed the instructions [here](https://github.com/radar/guides/blob/master/gem-development.md)
|
69
|
+
for using Bundler to create the gem.\n\n## INSTALL:\n\n* gem install castar\n\n##
|
70
|
+
LICENSE:\n\n(The MIT License)\n"
|
71
|
+
email:
|
72
|
+
- johnwilde@gmail.com
|
73
|
+
executables: []
|
74
|
+
extensions:
|
75
|
+
- ext/extconf.rb
|
76
|
+
extra_rdoc_files: []
|
77
|
+
files:
|
78
|
+
- .gitignore
|
79
|
+
- Gemfile
|
80
|
+
- README.markdown
|
81
|
+
- Rakefile
|
82
|
+
- benchmarks/benchmark_helper.rb
|
83
|
+
- benchmarks/benchmarker.rb
|
84
|
+
- benchmarks/example.rb
|
85
|
+
- benchmarks/map90.0.txt
|
86
|
+
- benchmarks/map90.1.txt
|
87
|
+
- castar.gemspec
|
88
|
+
- ext/extconf.rb
|
89
|
+
- ext/findpath.h
|
90
|
+
- ext/fsa.h
|
91
|
+
- ext/heyes_wrap.cxx
|
92
|
+
- ext/stlastar.h
|
93
|
+
- lib/castar.rb
|
94
|
+
- lib/castar/version.rb
|
95
|
+
- spec/castar_spec.rb
|
96
|
+
- spec/map_20.txt
|
97
|
+
- swig/buildRubyExtension.sh
|
98
|
+
- swig/heyes.i
|
99
|
+
homepage: ''
|
100
|
+
licenses: []
|
101
|
+
post_install_message:
|
102
|
+
rdoc_options: []
|
103
|
+
require_paths:
|
104
|
+
- lib
|
105
|
+
- ext
|
106
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
107
|
+
none: false
|
108
|
+
requirements:
|
109
|
+
- - ! '>='
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '0'
|
112
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - ! '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
requirements: []
|
119
|
+
rubyforge_project: castar
|
120
|
+
rubygems_version: 1.8.12
|
121
|
+
signing_key:
|
122
|
+
specification_version: 3
|
123
|
+
summary: Ruby interface to a C++ implementation of the A* algorithm
|
124
|
+
test_files:
|
125
|
+
- spec/castar_spec.rb
|
126
|
+
- spec/map_20.txt
|
127
|
+
has_rdoc:
|