theseus 1.0.2 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
-