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.
@@ -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].round, 0, canvas.width-1),
121
- clamp(p1[1].round, 0, canvas.height-1),
122
- clamp(p2[0].round, 0, canvas.width-1),
123
- clamp(p2[1].round, 0, canvas.height-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
- [x0, x1].min.ceil.upto([x0, x1].max.floor) do |x|
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
- min_y = 1_000_000
147
- max_y = -1_000_000
148
- points.each do |x,y|
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
- min_y = clamp(min_y, 0, canvas.height-1)
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
@@ -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 = 0x00FF
27
+ PRIMARY = 0x000000FF
33
28
 
34
29
  # bitmask identifying directional bits under the primary plane
35
- UNDER = 0xFF00
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 support weaving.)
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
- loop do
196
- @y = rand(@cells.length)
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
- braid(dead_end[0], dead_end[1])
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
- direction = next_direction or return !@generated
286
- nx, ny = move(@x, @y, direction)
287
-
288
- apply_move_at(@x, @y, direction)
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
- if from[0] < to[0]
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.sort_by { rand }[0,count]
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 braid(x, y) #:nodoc:
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
@@ -2,8 +2,8 @@ module Theseus
2
2
  # The current version of the Theseus library.
3
3
  module Version
4
4
  MAJOR = 1
5
- MINOR = 0
6
- TINY = 2
5
+ MINOR = 1
6
+ TINY = 0
7
7
 
8
8
  STRING = [MAJOR, MINOR, TINY].join(".")
9
9
  end
@@ -1,7 +1,7 @@
1
1
  require 'minitest/autorun'
2
2
  require 'theseus'
3
3
 
4
- class MazeTest < MiniTest::Unit::TestCase
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 -1, maze.dx(Theseus::Maze::W)
144
- assert_equal -1, maze.dx(Theseus::Maze::NW)
145
- assert_equal -1, maze.dx(Theseus::Maze::SW)
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 -1, maze.dy(Theseus::Maze::N)
158
- assert_equal -1, maze.dy(Theseus::Maze::NE)
159
- assert_equal -1, maze.dy(Theseus::Maze::NW)
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
- prerelease: false
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
- date: 2010-12-20 00:00:00 -07:00
18
- default_executable:
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
- prerelease: false
23
- requirement: &id001 !ruby/object:Gem::Requirement
24
- requirements:
25
- - - ~>
26
- - !ruby/object:Gem::Version
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
- version_requirements: *id001
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: jamis@jamisbuck.org
36
- executables:
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/ascii.rb
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
- has_rdoc: true
71
- homepage: http://github.com/jamis/theseus
72
- licenses: []
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
- segments:
84
- - 0
85
- version: "0"
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
- segments:
91
- - 0
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: 1.3.6
87
+ rubygems_version: 2.6.11
97
88
  signing_key:
98
- specification_version: 3
89
+ specification_version: 4
99
90
  summary: Maze generator for Ruby
100
91
  test_files: []
101
-