theseus 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +137 -0
- data/Rakefile +42 -0
- data/bin/theseus +262 -0
- data/examples/a-star-search.rb +106 -0
- data/lib/theseus.rb +6 -0
- data/lib/theseus/delta_maze.rb +45 -0
- data/lib/theseus/formatters/ascii.rb +41 -0
- data/lib/theseus/formatters/ascii/delta.rb +79 -0
- data/lib/theseus/formatters/ascii/orthogonal.rb +156 -0
- data/lib/theseus/formatters/ascii/sigma.rb +57 -0
- data/lib/theseus/formatters/ascii/upsilon.rb +67 -0
- data/lib/theseus/formatters/png.rb +183 -0
- data/lib/theseus/formatters/png/delta.rb +85 -0
- data/lib/theseus/formatters/png/orthogonal.rb +87 -0
- data/lib/theseus/formatters/png/sigma.rb +105 -0
- data/lib/theseus/formatters/png/upsilon.rb +137 -0
- data/lib/theseus/mask.rb +113 -0
- data/lib/theseus/maze.rb +855 -0
- data/lib/theseus/orthogonal_maze.rb +195 -0
- data/lib/theseus/path.rb +91 -0
- data/lib/theseus/sigma_maze.rb +107 -0
- data/lib/theseus/solvers/astar.rb +144 -0
- data/lib/theseus/solvers/backtracker.rb +79 -0
- data/lib/theseus/solvers/base.rb +95 -0
- data/lib/theseus/upsilon_maze.rb +37 -0
- data/lib/theseus/version.rb +10 -0
- data/test/maze_test.rb +193 -0
- metadata +104 -0
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'theseus/solvers/base'
|
2
|
+
|
3
|
+
module Theseus
|
4
|
+
module Solvers
|
5
|
+
# An implementation of a recursive backtracker for solving a maze. Although it will
|
6
|
+
# work (eventually) for multiply-connected mazes, it will almost certainly not
|
7
|
+
# return an optimal solution in that case. Thus, this solver is best suited only
|
8
|
+
# for "perfect" mazes (those with no loops).
|
9
|
+
#
|
10
|
+
# For mazes that contain loops, see the Theseus::Solvers::Astar class.
|
11
|
+
class Backtracker < Base
|
12
|
+
def initialize(maze, a=maze.start, b=maze.finish) #:nodoc:
|
13
|
+
super
|
14
|
+
@visits = Array.new(@maze.height) { Array.new(@maze.width, 0) }
|
15
|
+
@stack = []
|
16
|
+
end
|
17
|
+
|
18
|
+
VISIT_MASK = { false => 1, true => 2 }
|
19
|
+
|
20
|
+
def current_solution #:nodoc:
|
21
|
+
@stack[1..-1].map { |item| item[0] }
|
22
|
+
end
|
23
|
+
|
24
|
+
def step #:nodoc:
|
25
|
+
if @stack == [:fail]
|
26
|
+
return false
|
27
|
+
elsif @stack.empty?
|
28
|
+
@stack.push(:fail)
|
29
|
+
@stack.push([@a, @maze.potential_exits_at(@a[0], @a[1]).dup])
|
30
|
+
return @a.dup
|
31
|
+
elsif @stack.last[0] == @b
|
32
|
+
@solution = @stack[1..-1].map { |pt, tries| pt }
|
33
|
+
return false
|
34
|
+
else
|
35
|
+
x, y = @stack.last[0]
|
36
|
+
cell = @maze[x, y]
|
37
|
+
loop do
|
38
|
+
try = @stack.last[1].pop
|
39
|
+
|
40
|
+
if try.nil?
|
41
|
+
spot = @stack.pop
|
42
|
+
x, y = spot[0]
|
43
|
+
return :backtrack
|
44
|
+
elsif (cell & try) != 0
|
45
|
+
# is the current path an "under" path for the current cell (x,y)?
|
46
|
+
is_under = (try & Maze::UNDER != 0)
|
47
|
+
|
48
|
+
dir = is_under ? (try >> Maze::UNDER_SHIFT) : try
|
49
|
+
opposite = @maze.opposite(dir)
|
50
|
+
|
51
|
+
nx, ny = @maze.move(x, y, dir)
|
52
|
+
|
53
|
+
# is the new path an "under" path for the next cell (nx,ny)?
|
54
|
+
going_under = @maze[nx, ny] & (opposite << Maze::UNDER_SHIFT) != 0
|
55
|
+
|
56
|
+
# might be out of bounds, due to the entrance/exit passages
|
57
|
+
next if !@maze.valid?(nx, ny) || (@visits[ny][nx] & VISIT_MASK[going_under] != 0)
|
58
|
+
|
59
|
+
@visits[ny][nx] |= VISIT_MASK[going_under]
|
60
|
+
ncell = @maze[nx, ny]
|
61
|
+
p = [nx, ny]
|
62
|
+
|
63
|
+
if ncell & (opposite << Maze::UNDER_SHIFT) != 0 # underpass
|
64
|
+
unders = (ncell & Maze::UNDER) >> Maze::UNDER_SHIFT
|
65
|
+
exit_dir = unders & ~opposite
|
66
|
+
directions = [exit_dir << Maze::UNDER_SHIFT]
|
67
|
+
else
|
68
|
+
directions = @maze.potential_exits_at(nx, ny) - [@maze.opposite(dir)]
|
69
|
+
end
|
70
|
+
|
71
|
+
@stack.push([p, directions])
|
72
|
+
return p.dup
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'theseus/maze'
|
2
|
+
|
3
|
+
module Theseus
|
4
|
+
module Solvers
|
5
|
+
# The abstract superclass for solver implementations. It simply provides
|
6
|
+
# some helper methods that implementations would otherwise have to duplicate.
|
7
|
+
class Base
|
8
|
+
# The maze object that this solver will provide a solution for.
|
9
|
+
attr_reader :maze
|
10
|
+
|
11
|
+
# The point (2-tuple array) at which the solution path should begin.
|
12
|
+
attr_reader :a
|
13
|
+
|
14
|
+
# The point (2-tuple array) at which the solution path should end.
|
15
|
+
attr_reader :b
|
16
|
+
|
17
|
+
# Create a new solver instance for the given maze, using the given
|
18
|
+
# start (+a+) and finish (+b+) points. The solution will not be immediately
|
19
|
+
# generated; to do so, use the #step or #solve methods.
|
20
|
+
def initialize(maze, a=maze.start, b=maze.finish)
|
21
|
+
@maze = maze
|
22
|
+
@a = a
|
23
|
+
@b = b
|
24
|
+
@solution = nil
|
25
|
+
end
|
26
|
+
|
27
|
+
# Returns +true+ if the solution has been generated.
|
28
|
+
def solved?
|
29
|
+
@solution != nil
|
30
|
+
end
|
31
|
+
|
32
|
+
# Returns the solution path as an array of 2-tuples, beginning with #a and
|
33
|
+
# ending with #b. If the solution has not yet been generated, this will
|
34
|
+
# generate the solution first, and then return it.
|
35
|
+
def solution
|
36
|
+
solve unless solved?
|
37
|
+
@solution
|
38
|
+
end
|
39
|
+
|
40
|
+
# Generates the solution to the maze, and returns +self+. If the solution
|
41
|
+
# has already been generated, this does nothing.
|
42
|
+
def solve
|
43
|
+
while !solved?
|
44
|
+
step
|
45
|
+
end
|
46
|
+
|
47
|
+
self
|
48
|
+
end
|
49
|
+
|
50
|
+
# If the maze is solved, this yields each point in the solution, in order.
|
51
|
+
#
|
52
|
+
# If the maze has not yet been solved, this yields the result of calling
|
53
|
+
# #step, until the maze has been solved.
|
54
|
+
def each
|
55
|
+
if solved?
|
56
|
+
solution.each { |s| yield s }
|
57
|
+
else
|
58
|
+
yield s while s = step
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Returns the solution (or, if the solution is not yet fully generated,
|
63
|
+
# the current_solution) as a Theseus::Path object.
|
64
|
+
def to_path(options={})
|
65
|
+
path = @maze.new_path(options)
|
66
|
+
prev = @maze.entrance
|
67
|
+
|
68
|
+
(@solution || current_solution).each do |pt|
|
69
|
+
how = path.link(prev, pt)
|
70
|
+
path.set(pt, how)
|
71
|
+
prev = pt
|
72
|
+
end
|
73
|
+
|
74
|
+
how = path.link(prev, @maze.exit)
|
75
|
+
path.set(@maze.exit, how)
|
76
|
+
|
77
|
+
path
|
78
|
+
end
|
79
|
+
|
80
|
+
# Returns the current (potentially partial) solution to the maze. This
|
81
|
+
# is for use while the algorithm is running, so that the current best-solution
|
82
|
+
# may be inspected (or displayed).
|
83
|
+
def current_solution
|
84
|
+
raise NotImplementedError, "solver subclasses must implement #current_solution"
|
85
|
+
end
|
86
|
+
|
87
|
+
# Runs a single iteration of the solution algorithm. Returns +false+ if the
|
88
|
+
# algorithm has completed, and non-nil otherwise. The return value is
|
89
|
+
# algorithm-dependent.
|
90
|
+
def step
|
91
|
+
raise NotImplementedError, "solver subclasses must implement #step"
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'theseus/maze'
|
2
|
+
|
3
|
+
module Theseus
|
4
|
+
# An upsilon maze is one in which the field is tesselated into octogons and
|
5
|
+
# squares:
|
6
|
+
#
|
7
|
+
# _ _ _ _
|
8
|
+
# / \_/ \_/ \_/ \
|
9
|
+
# | |_| |_| |_| |
|
10
|
+
# \_/ \_/ \_/ \_/
|
11
|
+
# |_| |_| |_| |_|
|
12
|
+
# / \_/ \_/ \_/ \
|
13
|
+
# | |_| |_| |_| |
|
14
|
+
# \_/ \_/ \_/ \_/
|
15
|
+
#
|
16
|
+
# Upsilon mazes in Theseus support weaving, but not symmetry (yet).
|
17
|
+
#
|
18
|
+
# maze = Theseus::UpsilonMaze.generate(width: 10)
|
19
|
+
# puts maze
|
20
|
+
class UpsilonMaze < Maze
|
21
|
+
def potential_exits_at(x, y) #:nodoc:
|
22
|
+
if (x+y) % 2 == 0 # octogon
|
23
|
+
[N, S, E, W, NW, NE, SW, SE]
|
24
|
+
else # square
|
25
|
+
[N, S, E, W]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def perform_weave(from_x, from_y, to_x, to_y, direction) #:nodoc:
|
30
|
+
apply_move_at(to_x, to_y, direction << UNDER_SHIFT)
|
31
|
+
apply_move_at(to_x, to_y, opposite(direction) << UNDER_SHIFT)
|
32
|
+
|
33
|
+
nx, ny = move(to_x, to_y, direction)
|
34
|
+
[nx, ny, direction]
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/test/maze_test.rb
ADDED
@@ -0,0 +1,193 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'theseus'
|
3
|
+
|
4
|
+
class MazeTest < MiniTest::Unit::TestCase
|
5
|
+
def test_maze_without_explicit_height_uses_width
|
6
|
+
maze = Theseus::OrthogonalMaze.new(width: 10)
|
7
|
+
assert_equal 10, maze.width
|
8
|
+
assert_equal maze.width, maze.height
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_maze_without_explicit_width_uses_height
|
12
|
+
maze = Theseus::OrthogonalMaze.new(height: 10)
|
13
|
+
assert_equal 10, maze.height
|
14
|
+
assert_equal maze.height, maze.width
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_maze_is_initially_blank
|
18
|
+
maze = Theseus::OrthogonalMaze.new(width: 10)
|
19
|
+
assert !maze.generated?
|
20
|
+
|
21
|
+
zeros = 0
|
22
|
+
maze.height.times do |y|
|
23
|
+
maze.width.times do |x|
|
24
|
+
zeros += 1if maze[x, y] == 0
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
assert_equal 100, zeros
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_maze_created_with_generate_is_identical_to_maze_created_with_step
|
32
|
+
srand(14)
|
33
|
+
maze1 = Theseus::OrthogonalMaze.generate(width: 10)
|
34
|
+
assert maze1.generated?
|
35
|
+
|
36
|
+
srand(14)
|
37
|
+
maze2 = Theseus::OrthogonalMaze.new(width: 10)
|
38
|
+
maze2.step until maze2.generated?
|
39
|
+
|
40
|
+
assert_equal maze1.width, maze2.width
|
41
|
+
assert_equal maze1.height, maze2.height
|
42
|
+
|
43
|
+
differences = 0
|
44
|
+
|
45
|
+
maze1.width.times do |x|
|
46
|
+
maze1.height.times do |y|
|
47
|
+
differences += 1 unless maze1[x,y] == maze2[x,y]
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
assert_equal 0, differences
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_apply_move_at_should_combine_direction_with_existing_directions
|
55
|
+
maze = Theseus::OrthogonalMaze.new(width: 10)
|
56
|
+
|
57
|
+
maze[5,5] = Theseus::Maze::E
|
58
|
+
maze.apply_move_at(5, 5, Theseus::Maze::N)
|
59
|
+
assert_equal (Theseus::Maze::N | Theseus::Maze::E), maze[5,5]
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_apply_move_at_with_under_should_move_existing_directions_to_under_plane
|
63
|
+
maze = Theseus::OrthogonalMaze.new(width: 10)
|
64
|
+
|
65
|
+
maze[5,5] = Theseus::Maze::E
|
66
|
+
maze.apply_move_at(5, 5, :under)
|
67
|
+
assert_equal (Theseus::Maze::E << Theseus::Maze::UNDER_SHIFT), maze[5,5]
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_apply_move_at_with_x_symmetry_should_populate_x_mirror
|
71
|
+
maze = Theseus::OrthogonalMaze.new(width: 10, symmetry: :x)
|
72
|
+
|
73
|
+
maze.apply_move_at(1, 2, Theseus::Maze::E)
|
74
|
+
assert_equal Theseus::Maze::W, maze[8, 2]
|
75
|
+
|
76
|
+
maze.apply_move_at(2, 1, Theseus::Maze::NE)
|
77
|
+
assert_equal Theseus::Maze::NW, maze[7, 1]
|
78
|
+
|
79
|
+
maze.apply_move_at(2, 3, Theseus::Maze::N)
|
80
|
+
assert_equal Theseus::Maze::N, maze[7, 3]
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_apply_move_at_with_y_symmetry_should_populate_y_mirror
|
84
|
+
maze = Theseus::OrthogonalMaze.new(width: 10, symmetry: :y)
|
85
|
+
|
86
|
+
maze.apply_move_at(1, 2, Theseus::Maze::S)
|
87
|
+
assert_equal Theseus::Maze::N, maze[1, 7]
|
88
|
+
|
89
|
+
maze.apply_move_at(2, 1, Theseus::Maze::SW)
|
90
|
+
assert_equal Theseus::Maze::NW, maze[2, 8]
|
91
|
+
|
92
|
+
maze.apply_move_at(2, 3, Theseus::Maze::W)
|
93
|
+
assert_equal Theseus::Maze::W, maze[2, 6]
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_apply_move_at_with_xy_symmetry_should_populate_xy_mirror
|
97
|
+
maze = Theseus::OrthogonalMaze.new(width: 10, symmetry: :xy)
|
98
|
+
|
99
|
+
maze.apply_move_at(1, 2, Theseus::Maze::S)
|
100
|
+
assert_equal Theseus::Maze::N, maze[1, 7]
|
101
|
+
assert_equal Theseus::Maze::S, maze[8, 2]
|
102
|
+
assert_equal Theseus::Maze::N, maze[8, 7]
|
103
|
+
|
104
|
+
maze.apply_move_at(2, 1, Theseus::Maze::SW)
|
105
|
+
assert_equal Theseus::Maze::NW, maze[2, 8]
|
106
|
+
assert_equal Theseus::Maze::SE, maze[7, 1]
|
107
|
+
assert_equal Theseus::Maze::NE, maze[7, 8]
|
108
|
+
|
109
|
+
maze.apply_move_at(2, 3, Theseus::Maze::W)
|
110
|
+
assert_equal Theseus::Maze::W, maze[2, 6]
|
111
|
+
assert_equal Theseus::Maze::E, maze[7, 3]
|
112
|
+
assert_equal Theseus::Maze::E, maze[7, 6]
|
113
|
+
end
|
114
|
+
|
115
|
+
def test_apply_move_at_with_radial_symmetry_should_populate_radial_mirror
|
116
|
+
maze = Theseus::OrthogonalMaze.new(width: 10, symmetry: :radial)
|
117
|
+
|
118
|
+
maze.apply_move_at(1, 2, Theseus::Maze::S)
|
119
|
+
assert_equal Theseus::Maze::E, maze[2, 8]
|
120
|
+
assert_equal Theseus::Maze::W, maze[7, 1]
|
121
|
+
assert_equal Theseus::Maze::N, maze[8, 7]
|
122
|
+
|
123
|
+
maze.apply_move_at(2, 1, Theseus::Maze::SW)
|
124
|
+
assert_equal Theseus::Maze::SE, maze[1, 7]
|
125
|
+
assert_equal Theseus::Maze::NW, maze[8, 2]
|
126
|
+
assert_equal Theseus::Maze::NE, maze[7, 8]
|
127
|
+
|
128
|
+
maze.apply_move_at(2, 3, Theseus::Maze::W)
|
129
|
+
assert_equal Theseus::Maze::S, maze[3, 7]
|
130
|
+
assert_equal Theseus::Maze::N, maze[6, 2]
|
131
|
+
assert_equal Theseus::Maze::E, maze[7, 6]
|
132
|
+
end
|
133
|
+
|
134
|
+
def test_dx_east_should_increase
|
135
|
+
maze = Theseus::OrthogonalMaze.new(width: 10)
|
136
|
+
assert_equal 1, maze.dx(Theseus::Maze::E)
|
137
|
+
assert_equal 1, maze.dx(Theseus::Maze::NE)
|
138
|
+
assert_equal 1, maze.dx(Theseus::Maze::SE)
|
139
|
+
end
|
140
|
+
|
141
|
+
def test_dx_west_should_decrease
|
142
|
+
maze = Theseus::OrthogonalMaze.new(width: 10)
|
143
|
+
assert_equal -1, maze.dx(Theseus::Maze::W)
|
144
|
+
assert_equal -1, maze.dx(Theseus::Maze::NW)
|
145
|
+
assert_equal -1, maze.dx(Theseus::Maze::SW)
|
146
|
+
end
|
147
|
+
|
148
|
+
def test_dy_south_should_increase
|
149
|
+
maze = Theseus::OrthogonalMaze.new(width: 10)
|
150
|
+
assert_equal 1, maze.dy(Theseus::Maze::S)
|
151
|
+
assert_equal 1, maze.dy(Theseus::Maze::SE)
|
152
|
+
assert_equal 1, maze.dy(Theseus::Maze::SW)
|
153
|
+
end
|
154
|
+
|
155
|
+
def test_dy_north_should_decrease
|
156
|
+
maze = Theseus::OrthogonalMaze.new(width: 10)
|
157
|
+
assert_equal -1, maze.dy(Theseus::Maze::N)
|
158
|
+
assert_equal -1, maze.dy(Theseus::Maze::NE)
|
159
|
+
assert_equal -1, maze.dy(Theseus::Maze::NW)
|
160
|
+
end
|
161
|
+
|
162
|
+
def test_opposite_should_report_inverse_direction
|
163
|
+
maze = Theseus::OrthogonalMaze.new(width: 10)
|
164
|
+
assert_equal Theseus::Maze::N, maze.opposite(Theseus::Maze::S)
|
165
|
+
assert_equal Theseus::Maze::NE, maze.opposite(Theseus::Maze::SW)
|
166
|
+
assert_equal Theseus::Maze::E, maze.opposite(Theseus::Maze::W)
|
167
|
+
assert_equal Theseus::Maze::SE, maze.opposite(Theseus::Maze::NW)
|
168
|
+
assert_equal Theseus::Maze::S, maze.opposite(Theseus::Maze::N)
|
169
|
+
assert_equal Theseus::Maze::SW, maze.opposite(Theseus::Maze::NE)
|
170
|
+
assert_equal Theseus::Maze::W, maze.opposite(Theseus::Maze::E)
|
171
|
+
assert_equal Theseus::Maze::NW, maze.opposite(Theseus::Maze::SE)
|
172
|
+
end
|
173
|
+
|
174
|
+
def test_step_should_populate_current_cell_and_next_cell
|
175
|
+
maze = Theseus::OrthogonalMaze.new(width: 10)
|
176
|
+
|
177
|
+
cx, cy = maze.x, maze.y
|
178
|
+
assert cx >= 0 && cx < maze.width
|
179
|
+
assert cy >= 0 && cy < maze.height
|
180
|
+
assert_equal 0, maze[cx, cy]
|
181
|
+
|
182
|
+
assert maze.step
|
183
|
+
|
184
|
+
direction = maze[cx, cy]
|
185
|
+
refute_equal 0, direction
|
186
|
+
|
187
|
+
nx, ny = maze.move(cx, cy, direction)
|
188
|
+
refute_equal [nx, ny], [cx, cy]
|
189
|
+
assert_equal [nx, ny], [maze.x, maze.y]
|
190
|
+
|
191
|
+
assert_equal maze.opposite(direction), maze[nx, ny]
|
192
|
+
end
|
193
|
+
end
|
metadata
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: theseus
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 1
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
version: 1.0.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Jamis Buck
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-12-19 00:00:00 -07:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: chunky_png
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ~>
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
segments:
|
29
|
+
- 0
|
30
|
+
- 12
|
31
|
+
- 0
|
32
|
+
version: 0.12.0
|
33
|
+
type: :runtime
|
34
|
+
version_requirements: *id001
|
35
|
+
description: Theseus is a library for building random mazes.
|
36
|
+
email: jamis@jamisbuck.org
|
37
|
+
executables:
|
38
|
+
- theseus
|
39
|
+
extensions: []
|
40
|
+
|
41
|
+
extra_rdoc_files: []
|
42
|
+
|
43
|
+
files:
|
44
|
+
- README.rdoc
|
45
|
+
- Rakefile
|
46
|
+
- lib/theseus/delta_maze.rb
|
47
|
+
- lib/theseus/formatters/ascii/delta.rb
|
48
|
+
- lib/theseus/formatters/ascii/orthogonal.rb
|
49
|
+
- lib/theseus/formatters/ascii/sigma.rb
|
50
|
+
- lib/theseus/formatters/ascii/upsilon.rb
|
51
|
+
- lib/theseus/formatters/ascii.rb
|
52
|
+
- lib/theseus/formatters/png/delta.rb
|
53
|
+
- lib/theseus/formatters/png/orthogonal.rb
|
54
|
+
- lib/theseus/formatters/png/sigma.rb
|
55
|
+
- lib/theseus/formatters/png/upsilon.rb
|
56
|
+
- lib/theseus/formatters/png.rb
|
57
|
+
- lib/theseus/mask.rb
|
58
|
+
- lib/theseus/maze.rb
|
59
|
+
- lib/theseus/orthogonal_maze.rb
|
60
|
+
- lib/theseus/path.rb
|
61
|
+
- lib/theseus/sigma_maze.rb
|
62
|
+
- lib/theseus/solvers/astar.rb
|
63
|
+
- lib/theseus/solvers/backtracker.rb
|
64
|
+
- lib/theseus/solvers/base.rb
|
65
|
+
- lib/theseus/upsilon_maze.rb
|
66
|
+
- lib/theseus/version.rb
|
67
|
+
- lib/theseus.rb
|
68
|
+
- examples/a-star-search.rb
|
69
|
+
- bin/theseus
|
70
|
+
- test/maze_test.rb
|
71
|
+
has_rdoc: true
|
72
|
+
homepage: http://github.com/jamis/theseus
|
73
|
+
licenses: []
|
74
|
+
|
75
|
+
post_install_message:
|
76
|
+
rdoc_options: []
|
77
|
+
|
78
|
+
require_paths:
|
79
|
+
- lib
|
80
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ">="
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
segments:
|
86
|
+
- 0
|
87
|
+
version: "0"
|
88
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ">="
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
segments:
|
94
|
+
- 0
|
95
|
+
version: "0"
|
96
|
+
requirements:
|
97
|
+
- Ruby 1.9
|
98
|
+
rubyforge_project:
|
99
|
+
rubygems_version: 1.3.7
|
100
|
+
signing_key:
|
101
|
+
specification_version: 3
|
102
|
+
summary: Maze generator for Ruby
|
103
|
+
test_files: []
|
104
|
+
|