theseus 1.0.2 → 1.1.0
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.
- checksums.yaml +7 -0
- data/Rakefile +1 -24
- data/bin/theseus +2 -259
- data/lib/theseus/algorithms/base.rb +31 -0
- data/lib/theseus/algorithms/kruskal.rb +81 -0
- data/lib/theseus/algorithms/prim.rb +81 -0
- data/lib/theseus/algorithms/recursive_backtracker.rb +80 -0
- data/lib/theseus/cli.rb +377 -0
- data/lib/theseus/formatters/png.rb +13 -45
- data/lib/theseus/maze.rb +74 -103
- data/lib/theseus/version.rb +2 -2
- data/test/maze_test.rb +9 -9
- metadata +48 -58
@@ -117,25 +117,21 @@ module Theseus
|
|
117
117
|
# within the canvas' bounds.
|
118
118
|
def line(canvas, p1, p2, color)
|
119
119
|
canvas.line(
|
120
|
-
clamp(p1[0].
|
121
|
-
clamp(p1[1].
|
122
|
-
clamp(p2[0].
|
123
|
-
clamp(p2[1].
|
120
|
+
clamp(p1[0].floor, 0, canvas.width-1),
|
121
|
+
clamp(p1[1].floor, 0, canvas.height-1),
|
122
|
+
clamp(p2[0].floor, 0, canvas.width-1),
|
123
|
+
clamp(p2[1].floor, 0, canvas.height-1),
|
124
124
|
color)
|
125
125
|
end
|
126
126
|
|
127
127
|
# Fills the rectangle defined by the given coordinates with the given color.
|
128
128
|
# The coordinates are clamped to lie within the canvas' bounds.
|
129
129
|
def fill_rect(canvas, x0, y0, x1, y1, color)
|
130
|
-
x0 = clamp(x0, 0, canvas.width-1)
|
131
|
-
y0 = clamp(y0, 0, canvas.height-1)
|
132
|
-
x1 = clamp(x1, 0, canvas.width-1)
|
133
|
-
y1 = clamp(y1, 0, canvas.height-1)
|
134
|
-
|
135
|
-
[y0, y1].min.ceil.upto([y0, y1].max.floor) do |y|
|
136
|
-
canvas.point(x, y, color)
|
137
|
-
end
|
138
|
-
end
|
130
|
+
x0 = clamp(x0, 0, canvas.width-1).floor
|
131
|
+
y0 = clamp(y0, 0, canvas.height-1).floor
|
132
|
+
x1 = clamp(x1, 0, canvas.width-1).floor
|
133
|
+
y1 = clamp(y1, 0, canvas.height-1).floor
|
134
|
+
canvas.rect(x0, y0, x1, y1, color, color)
|
139
135
|
end
|
140
136
|
|
141
137
|
# Fills the polygon defined by the +points+ array, with the given +color+.
|
@@ -143,40 +139,12 @@ module Theseus
|
|
143
139
|
# polygon. It is assumed that the polygon is closed. All points are
|
144
140
|
# clamped (naively) to lie within the canvas' bounds.
|
145
141
|
def fill_poly(canvas, points, color)
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
min_y = y if y < min_y
|
150
|
-
max_y = y if y > max_y
|
142
|
+
clamped = points.map do |(x, y)|
|
143
|
+
[ clamp(x.floor, 0, canvas.width - 1),
|
144
|
+
clamp(y.floor, 0, canvas.height - 1) ]
|
151
145
|
end
|
152
146
|
|
153
|
-
|
154
|
-
max_y = clamp(max_y, 0, canvas.height-1)
|
155
|
-
|
156
|
-
min_y.floor.upto(max_y.ceil) do |y|
|
157
|
-
nodes = []
|
158
|
-
|
159
|
-
prev = points.last
|
160
|
-
points.each do |point|
|
161
|
-
if point[1] < y && prev[1] >= y || prev[1] < y && point[1] >= y
|
162
|
-
nodes << (point[0] + (y - point[1]).to_f / (prev[1] - point[1]) * (prev[0] - point[0]))
|
163
|
-
end
|
164
|
-
prev = point
|
165
|
-
end
|
166
|
-
|
167
|
-
next if nodes.empty?
|
168
|
-
nodes.sort!
|
169
|
-
|
170
|
-
prev = nil
|
171
|
-
0.step(nodes.length-1, 2) do |a|
|
172
|
-
x1, x2 = nodes[a], nodes[a+1]
|
173
|
-
x1, x2 = x2, x1 if x1 > x2
|
174
|
-
next if x1 < 0 || x2 >= canvas.width
|
175
|
-
x1.ceil.upto(x2.floor) do |x|
|
176
|
-
canvas.point(x, y, color)
|
177
|
-
end
|
178
|
-
end
|
179
|
-
end
|
147
|
+
canvas.polygon(clamped, color, color)
|
180
148
|
end
|
181
149
|
end
|
182
150
|
end
|
data/lib/theseus/maze.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'theseus/mask'
|
2
2
|
require 'theseus/path'
|
3
|
+
require 'theseus/algorithms/recursive_backtracker'
|
3
4
|
|
4
5
|
module Theseus
|
5
6
|
# Theseus::Maze is an abstract class, intended to act solely as a superclass
|
@@ -12,12 +13,6 @@ module Theseus
|
|
12
13
|
# in the high byte (corresponding to the UNDER bitmask) represent passages
|
13
14
|
# that are passing under this cell. (Under/over passages are controlled via the
|
14
15
|
# #weave setting, and are not supported by all maze types.)
|
15
|
-
#
|
16
|
-
# Mazes are generated using the recursive backtracking algorithm, which is fast,
|
17
|
-
# quite customizable, easily generalized to a variety of different maze types,
|
18
|
-
# and gives generally good results. On the down side, the current implementation
|
19
|
-
# will not regularly generate very challenging mazes, compared to human-built
|
20
|
-
# mazes of the same size.
|
21
16
|
class Maze
|
22
17
|
N = 0x01 # North
|
23
18
|
S = 0x02 # South
|
@@ -29,15 +24,22 @@ module Theseus
|
|
29
24
|
SE = 0x80 # Southeast
|
30
25
|
|
31
26
|
# bitmask identifying directional bits on the primary plane
|
32
|
-
PRIMARY
|
27
|
+
PRIMARY = 0x000000FF
|
33
28
|
|
34
29
|
# bitmask identifying directional bits under the primary plane
|
35
|
-
UNDER
|
30
|
+
UNDER = 0x0000FF00
|
31
|
+
|
32
|
+
# bits reserved for use by individual algorithm implementations
|
33
|
+
RESERVED = 0xFFFF0000
|
36
34
|
|
37
35
|
# The size of the PRIMARY bitmask (e.g. how far to the left the
|
38
36
|
# UNDER bitmask is shifted).
|
39
37
|
UNDER_SHIFT = 8
|
40
38
|
|
39
|
+
# The algorithm object used to generate this maze. Defaults to
|
40
|
+
# an instance of Algorithms::RecursiveBacktracker.
|
41
|
+
attr_reader :algorithm
|
42
|
+
|
41
43
|
# The width of the maze (number of columns).
|
42
44
|
#
|
43
45
|
# In general, it is safest to use the #row_length method for a particular
|
@@ -100,14 +102,6 @@ module Theseus
|
|
100
102
|
# to the maze, and generally defaults to the lower-right corner.
|
101
103
|
attr_reader :exit
|
102
104
|
|
103
|
-
# The x-coordinate that the generation algorithm will consider next.
|
104
|
-
# This value is meaningless once a maze has been generated.
|
105
|
-
attr_reader :x
|
106
|
-
|
107
|
-
# The y-coordinate that the generation algorithm will consider next.
|
108
|
-
# This value is meaningless once a maze has been generated.
|
109
|
-
attr_reader :y
|
110
|
-
|
111
105
|
# A short-hand method for creating a new maze object and causing it to
|
112
106
|
# be generated, in one step. Returns the newly generated maze.
|
113
107
|
def self.generate(options={})
|
@@ -123,6 +117,9 @@ module Theseus
|
|
123
117
|
# maze types count columns and rows differently; you'll
|
124
118
|
# want to see individual maze types for more info.
|
125
119
|
# [:height] The number of rows in the maze.
|
120
|
+
# [:algorithm] The maze algorithm to use. This should be a class,
|
121
|
+
# adhering to the interface described by Theseus::Algorithms::Base.
|
122
|
+
# It defaults to Theseus::Algorithms::RecursiveBacktracker.
|
126
123
|
# [:symmetry] The symmetry to be used when generating the maze. This
|
127
124
|
# defaults to +:none+, but may also be +:x+ (to have the
|
128
125
|
# maze mirrored across the x-axis), +:y+ (to mirror the
|
@@ -140,12 +137,14 @@ module Theseus
|
|
140
137
|
# [:mask] An instance of Theseus::Mask (or something that acts
|
141
138
|
# similarly). This can be used to constrain the maze so that
|
142
139
|
# it fills or avoids specific areas, so that shapes and
|
143
|
-
# patterns can be made.
|
140
|
+
# patterns can be made. (NOTE: not all algorithms support
|
141
|
+
# masks.)
|
144
142
|
# [:weave] An integer between 0 and 100 (inclusive) indicating how
|
145
143
|
# frequently passages move under or over other passages.
|
146
144
|
# A 0 means the passages will never move over/under other
|
147
145
|
# passages, while a 100 means they will do so as often
|
148
|
-
# as possible. (NOTE: not all maze types
|
146
|
+
# as possible. (NOTE: not all maze types and algorithms
|
147
|
+
# support weaving.)
|
149
148
|
# [:braid] An integer between 0 and 100 (inclusive) representing
|
150
149
|
# the percentage of dead-ends that should be removed after
|
151
150
|
# the maze has been generated. Dead-ends are removed by
|
@@ -175,6 +174,8 @@ module Theseus
|
|
175
174
|
# allowing you to then set the contents of the maze by hand,
|
176
175
|
# using the #[]= method.
|
177
176
|
def initialize(options={})
|
177
|
+
@deadends = nil
|
178
|
+
|
178
179
|
@width = (options[:width] || 10).to_i
|
179
180
|
@height = (options[:height] || 10).to_i
|
180
181
|
|
@@ -192,14 +193,8 @@ module Theseus
|
|
192
193
|
@entrance = options[:entrance] || default_entrance
|
193
194
|
@exit = options[:exit] || default_exit
|
194
195
|
|
195
|
-
|
196
|
-
|
197
|
-
@x = rand(@cells[@y].length)
|
198
|
-
break if valid?(@x, @y)
|
199
|
-
end
|
200
|
-
|
201
|
-
@tries = potential_exits_at(@x, @y).sort_by { rand }
|
202
|
-
@stack = []
|
196
|
+
algorithm_class = options[:algorithm] || Algorithms::RecursiveBacktracker
|
197
|
+
@algorithm = algorithm_class.new(self, options)
|
203
198
|
|
204
199
|
@generated = options[:prebuilt]
|
205
200
|
end
|
@@ -276,29 +271,17 @@ module Theseus
|
|
276
271
|
|
277
272
|
if @deadends && @deadends.any?
|
278
273
|
dead_end = @deadends.pop
|
279
|
-
|
280
|
-
|
274
|
+
braid_cell(dead_end[0], dead_end[1])
|
275
|
+
|
281
276
|
@generated = @deadends.empty?
|
282
277
|
return !@generated
|
283
278
|
end
|
284
279
|
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
# if (nx,ny) is already visited, then we're weaving (moving either over
|
291
|
-
# or under the existing passage).
|
292
|
-
nx, ny, direction = perform_weave(@x, @y, nx, ny, direction) if @cells[ny][nx] != 0
|
293
|
-
|
294
|
-
apply_move_at(nx, ny, opposite(direction))
|
295
|
-
|
296
|
-
@stack.push([@x, @y, @tries])
|
297
|
-
@tries = potential_exits_at(nx, ny).sort_by { rand }
|
298
|
-
@tries.push direction if @tries.include?(direction) unless rand(100) < @randomness
|
299
|
-
@x, @y = nx, ny
|
300
|
-
|
301
|
-
return true
|
280
|
+
if @algorithm.step
|
281
|
+
return true
|
282
|
+
else
|
283
|
+
return finish!
|
284
|
+
end
|
302
285
|
end
|
303
286
|
|
304
287
|
# Returns +true+ if the maze has been generated.
|
@@ -349,7 +332,7 @@ module Theseus
|
|
349
332
|
# 1. The coordinates lie within the maze's bounds, and
|
350
333
|
# 2. The current mask for the maze does not restrict the location.
|
351
334
|
#
|
352
|
-
# If the maze wraps in x, the x coordinate is unconstrained and will be
|
335
|
+
# If the maze wraps in x, the x coordinate is unconstrained and will be
|
353
336
|
# mapped (via modulo) to the bounds. Similarly, if the maze wraps in y,
|
354
337
|
# the y coordinate will be unconstrained.
|
355
338
|
def valid?(x, y)
|
@@ -587,7 +570,21 @@ module Theseus
|
|
587
570
|
# Returns the direction of +to+ relative to +from+. +to+ and +from+
|
588
571
|
# are both points (2-tuples).
|
589
572
|
def relative_direction(from, to)
|
590
|
-
|
573
|
+
# first, look for the case where the maze wraps, and from and to
|
574
|
+
# are on opposite sites of the grid.
|
575
|
+
if wrap_x? && from[1] == to[1] && (from[0] == 0 || to[0] == 0) && (from[0] == @width-1 || to[0] == @width-1)
|
576
|
+
if from[0] < to[0]
|
577
|
+
W
|
578
|
+
else
|
579
|
+
E
|
580
|
+
end
|
581
|
+
elsif wrap_y? && from[0] == to[0] && (from[1] == 0 || to[1] == 0) && (from[1] == @height-1 || to[1] == @height-1)
|
582
|
+
if from[1] < to[1]
|
583
|
+
N
|
584
|
+
else
|
585
|
+
S
|
586
|
+
end
|
587
|
+
elsif from[0] < to[0]
|
591
588
|
if from[1] < to[1]
|
592
589
|
SE
|
593
590
|
elsif from[1] > to[1]
|
@@ -670,6 +667,32 @@ module Theseus
|
|
670
667
|
generated? ? "generated" : "not generated"]
|
671
668
|
end
|
672
669
|
|
670
|
+
# Returns +true+ if a weave may be applied at (thru_x,thru_y) when moving
|
671
|
+
# from (from_x,from_y) in +direction+. This will be true if the thru cell
|
672
|
+
# does not already have anything in its UNDER plane, and if the cell
|
673
|
+
# on the far side of thru is valid and blank.
|
674
|
+
#
|
675
|
+
# Subclasses may need to override this method if special interpretations
|
676
|
+
# for +direction+ need to be considered (see SigmaMaze).
|
677
|
+
def weave_allowed?(from_x, from_y, thru_x, thru_y, direction) #:nodoc:
|
678
|
+
nx2, ny2 = move(thru_x, thru_y, direction)
|
679
|
+
return (@cells[thru_y][thru_x] & UNDER == 0) && valid?(nx2, ny2) && @cells[ny2][nx2] == 0
|
680
|
+
end
|
681
|
+
|
682
|
+
def perform_weave(from_x, from_y, to_x, to_y, direction) #:nodoc:
|
683
|
+
if rand(2) == 0 # move under existing passage
|
684
|
+
apply_move_at(to_x, to_y, direction << UNDER_SHIFT)
|
685
|
+
apply_move_at(to_x, to_y, opposite(direction) << UNDER_SHIFT)
|
686
|
+
else # move over existing passage
|
687
|
+
apply_move_at(to_x, to_y, :under)
|
688
|
+
apply_move_at(to_x, to_y, direction)
|
689
|
+
apply_move_at(to_x, to_y, opposite(direction))
|
690
|
+
end
|
691
|
+
|
692
|
+
nx, ny = move(to_x, to_y, direction)
|
693
|
+
[nx, ny, direction]
|
694
|
+
end
|
695
|
+
|
673
696
|
private
|
674
697
|
|
675
698
|
# Not all maze types support symmetry. If a subclass supports any of the
|
@@ -698,7 +721,7 @@ module Theseus
|
|
698
721
|
count = ends.length * @braid / 100
|
699
722
|
count = 1 if count < 1
|
700
723
|
|
701
|
-
ends.
|
724
|
+
ends.shuffle[0,count]
|
702
725
|
end
|
703
726
|
|
704
727
|
# Calculate the default entrance, by looking for the upper-leftmost point.
|
@@ -723,34 +746,6 @@ module Theseus
|
|
723
746
|
[0, 0] # if every cell is masked, then 0,0 is as good as any!
|
724
747
|
end
|
725
748
|
|
726
|
-
# Returns the next direction that ought to be attempted by the recursive
|
727
|
-
# backtracker. This will also handle the backtracking. If there are no
|
728
|
-
# more directions to attempt, and the stack is empty, this will return +nil+.
|
729
|
-
def next_direction #:nodoc:
|
730
|
-
loop do
|
731
|
-
direction = @tries.pop
|
732
|
-
nx, ny = move(@x, @y, direction)
|
733
|
-
|
734
|
-
if valid?(nx, ny) && (@cells[@y][@x] & (direction | (direction << UNDER_SHIFT)) == 0)
|
735
|
-
if @cells[ny][nx] == 0
|
736
|
-
return direction
|
737
|
-
elsif !dead?(@cells[ny][nx]) && @weave > 0 && rand(100) < @weave
|
738
|
-
# see if we can weave over/under the cell at (nx,ny)
|
739
|
-
return direction if weave_allowed?(@x, @y, nx, ny, direction)
|
740
|
-
end
|
741
|
-
end
|
742
|
-
|
743
|
-
while @tries.empty?
|
744
|
-
if @stack.empty?
|
745
|
-
finish!
|
746
|
-
return nil
|
747
|
-
else
|
748
|
-
@x, @y, @tries = @stack.pop
|
749
|
-
end
|
750
|
-
end
|
751
|
-
end
|
752
|
-
end
|
753
|
-
|
754
749
|
def move_symmetrically_in_x(x, y, direction) #:nodoc:
|
755
750
|
row_width = @cells[y].length
|
756
751
|
if direction == :under
|
@@ -802,6 +797,8 @@ module Theseus
|
|
802
797
|
|
803
798
|
@deadends = deadends_to_braid
|
804
799
|
@generated = @deadends.empty?
|
800
|
+
|
801
|
+
return !@generated
|
805
802
|
end
|
806
803
|
|
807
804
|
# If (x,y) is not a dead-end, this does nothing. Otherwise, it extends the
|
@@ -809,7 +806,7 @@ module Theseus
|
|
809
806
|
#
|
810
807
|
# TODO: look for the direction that results in the longest loop.
|
811
808
|
# might be kind of spendy, but worth trying, at least.
|
812
|
-
def
|
809
|
+
def braid_cell(x, y) #:nodoc:
|
813
810
|
return unless dead?(@cells[y][x])
|
814
811
|
tries = potential_exits_at(x, y)
|
815
812
|
[opposite(@cells[y][x]), *tries].each do |try|
|
@@ -825,31 +822,5 @@ module Theseus
|
|
825
822
|
end
|
826
823
|
end
|
827
824
|
|
828
|
-
# Returns +true+ if a weave may be applied at (thru_x,thru_y) when moving
|
829
|
-
# from (from_x,from_y) in +direction+. This will be true if the thru cell
|
830
|
-
# does not already have anything in its UNDER plane, and if the cell
|
831
|
-
# on the far side of thru is valid and blank.
|
832
|
-
#
|
833
|
-
# Subclasses may need to override this method if special interpretations
|
834
|
-
# for +direction+ need to be considered (see SigmaMaze).
|
835
|
-
def weave_allowed?(from_x, from_y, thru_x, thru_y, direction) #:nodoc:
|
836
|
-
nx2, ny2 = move(thru_x, thru_y, direction)
|
837
|
-
return (@cells[thru_y][thru_x] & UNDER == 0) && valid?(nx2, ny2) && @cells[ny2][nx2] == 0
|
838
|
-
end
|
839
|
-
|
840
|
-
def perform_weave(from_x, from_y, to_x, to_y, direction) #:nodoc:
|
841
|
-
if rand(2) == 0 # move under existing passage
|
842
|
-
apply_move_at(to_x, to_y, direction << UNDER_SHIFT)
|
843
|
-
apply_move_at(to_x, to_y, opposite(direction) << UNDER_SHIFT)
|
844
|
-
else # move over existing passage
|
845
|
-
apply_move_at(to_x, to_y, :under)
|
846
|
-
apply_move_at(to_x, to_y, direction)
|
847
|
-
apply_move_at(to_x, to_y, opposite(direction))
|
848
|
-
end
|
849
|
-
|
850
|
-
nx, ny = move(to_x, to_y, direction)
|
851
|
-
[nx, ny, direction]
|
852
|
-
end
|
853
|
-
|
854
825
|
end
|
855
826
|
end
|
data/lib/theseus/version.rb
CHANGED
data/test/maze_test.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'minitest/autorun'
|
2
2
|
require 'theseus'
|
3
3
|
|
4
|
-
class MazeTest <
|
4
|
+
class MazeTest < Minitest::Test
|
5
5
|
def test_maze_without_explicit_height_uses_width
|
6
6
|
maze = Theseus::OrthogonalMaze.new(width: 10)
|
7
7
|
assert_equal 10, maze.width
|
@@ -140,9 +140,9 @@ class MazeTest < MiniTest::Unit::TestCase
|
|
140
140
|
|
141
141
|
def test_dx_west_should_decrease
|
142
142
|
maze = Theseus::OrthogonalMaze.new(width: 10)
|
143
|
-
assert_equal
|
144
|
-
assert_equal
|
145
|
-
assert_equal
|
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
146
|
end
|
147
147
|
|
148
148
|
def test_dy_south_should_increase
|
@@ -154,9 +154,9 @@ class MazeTest < MiniTest::Unit::TestCase
|
|
154
154
|
|
155
155
|
def test_dy_north_should_decrease
|
156
156
|
maze = Theseus::OrthogonalMaze.new(width: 10)
|
157
|
-
assert_equal
|
158
|
-
assert_equal
|
159
|
-
assert_equal
|
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
160
|
end
|
161
161
|
|
162
162
|
def test_opposite_should_report_inverse_direction
|
@@ -174,7 +174,7 @@ class MazeTest < MiniTest::Unit::TestCase
|
|
174
174
|
def test_step_should_populate_current_cell_and_next_cell
|
175
175
|
maze = Theseus::OrthogonalMaze.new(width: 10)
|
176
176
|
|
177
|
-
cx, cy = maze.x, maze.y
|
177
|
+
cx, cy = maze.algorithm.x, maze.algorithm.y
|
178
178
|
assert cx >= 0 && cx < maze.width
|
179
179
|
assert cy >= 0 && cy < maze.height
|
180
180
|
assert_equal 0, maze[cx, cy]
|
@@ -186,7 +186,7 @@ class MazeTest < MiniTest::Unit::TestCase
|
|
186
186
|
|
187
187
|
nx, ny = maze.move(cx, cy, direction)
|
188
188
|
refute_equal [nx, ny], [cx, cy]
|
189
|
-
assert_equal [nx, ny], [maze.x, maze.y]
|
189
|
+
assert_equal [nx, ny], [maze.algorithm.x, maze.algorithm.y]
|
190
190
|
|
191
191
|
assert_equal maze.opposite(direction), maze[nx, ny]
|
192
192
|
end
|
metadata
CHANGED
@@ -1,58 +1,58 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: theseus
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
segments:
|
6
|
-
- 1
|
7
|
-
- 0
|
8
|
-
- 2
|
9
|
-
version: 1.0.2
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.1.0
|
10
5
|
platform: ruby
|
11
|
-
authors:
|
6
|
+
authors:
|
12
7
|
- Jamis Buck
|
13
8
|
autorequire:
|
14
9
|
bindir: bin
|
15
10
|
cert_chain: []
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
dependencies:
|
20
|
-
- !ruby/object:Gem::Dependency
|
11
|
+
date: 2018-02-24 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
21
14
|
name: chunky_png
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
segments:
|
28
|
-
- 0
|
29
|
-
- 12
|
30
|
-
- 0
|
31
|
-
version: 0.12.0
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.3'
|
32
20
|
type: :runtime
|
33
|
-
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.3'
|
34
27
|
description: Theseus is a library for building random mazes.
|
35
|
-
email:
|
36
|
-
|
28
|
+
email:
|
29
|
+
- jamis@jamisbuck.org
|
30
|
+
executables:
|
37
31
|
- theseus
|
38
32
|
extensions: []
|
39
|
-
|
40
33
|
extra_rdoc_files: []
|
41
|
-
|
42
|
-
files:
|
34
|
+
files:
|
43
35
|
- README.rdoc
|
44
36
|
- Rakefile
|
37
|
+
- bin/theseus
|
38
|
+
- examples/a-star-search.rb
|
39
|
+
- lib/theseus.rb
|
40
|
+
- lib/theseus/algorithms/base.rb
|
41
|
+
- lib/theseus/algorithms/kruskal.rb
|
42
|
+
- lib/theseus/algorithms/prim.rb
|
43
|
+
- lib/theseus/algorithms/recursive_backtracker.rb
|
44
|
+
- lib/theseus/cli.rb
|
45
45
|
- lib/theseus/delta_maze.rb
|
46
|
+
- lib/theseus/formatters/ascii.rb
|
46
47
|
- lib/theseus/formatters/ascii/delta.rb
|
47
48
|
- lib/theseus/formatters/ascii/orthogonal.rb
|
48
49
|
- lib/theseus/formatters/ascii/sigma.rb
|
49
50
|
- lib/theseus/formatters/ascii/upsilon.rb
|
50
|
-
- lib/theseus/formatters/
|
51
|
+
- lib/theseus/formatters/png.rb
|
51
52
|
- lib/theseus/formatters/png/delta.rb
|
52
53
|
- lib/theseus/formatters/png/orthogonal.rb
|
53
54
|
- lib/theseus/formatters/png/sigma.rb
|
54
55
|
- lib/theseus/formatters/png/upsilon.rb
|
55
|
-
- lib/theseus/formatters/png.rb
|
56
56
|
- lib/theseus/mask.rb
|
57
57
|
- lib/theseus/maze.rb
|
58
58
|
- lib/theseus/orthogonal_maze.rb
|
@@ -63,39 +63,29 @@ files:
|
|
63
63
|
- lib/theseus/solvers/base.rb
|
64
64
|
- lib/theseus/upsilon_maze.rb
|
65
65
|
- lib/theseus/version.rb
|
66
|
-
- lib/theseus.rb
|
67
|
-
- examples/a-star-search.rb
|
68
|
-
- bin/theseus
|
69
66
|
- test/maze_test.rb
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
67
|
+
homepage: https://github.com/jamis/theseus
|
68
|
+
licenses:
|
69
|
+
- MIT
|
70
|
+
metadata: {}
|
74
71
|
post_install_message:
|
75
72
|
rdoc_options: []
|
76
|
-
|
77
|
-
require_paths:
|
73
|
+
require_paths:
|
78
74
|
- lib
|
79
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
80
|
-
requirements:
|
75
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
76
|
+
requirements:
|
81
77
|
- - ">="
|
82
|
-
- !ruby/object:Gem::Version
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
87
|
-
requirements:
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: '0'
|
80
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
81
|
+
requirements:
|
88
82
|
- - ">="
|
89
|
-
- !ruby/object:Gem::Version
|
90
|
-
|
91
|
-
|
92
|
-
version: "0"
|
93
|
-
requirements:
|
94
|
-
- Ruby 1.9
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: '0'
|
85
|
+
requirements: []
|
95
86
|
rubyforge_project:
|
96
|
-
rubygems_version:
|
87
|
+
rubygems_version: 2.6.11
|
97
88
|
signing_key:
|
98
|
-
specification_version:
|
89
|
+
specification_version: 4
|
99
90
|
summary: Maze generator for Ruby
|
100
91
|
test_files: []
|
101
|
-
|