subparry_labyrinth_solver 1.0.2 → 1.0.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 73679ebec7ed8d1f1a435bf025892af34ccf8acdaf95937d97837e96b15cb77a
4
- data.tar.gz: 78551e9bb1b47cb0476ed233062a9458afb1497b8ec227e081028bf4d51846e7
3
+ metadata.gz: d0bf1b3d99443815ae5ff546b0abbd55512351f75ddb9d7de6299a2166c6f796
4
+ data.tar.gz: 4c7f159471b6f6e9c24178cd8d165f60e8a593f6f89160e92720e6c826e9a747
5
5
  SHA512:
6
- metadata.gz: 35642607e49c14134a39ac9f39071e93b96d1448a8c2ac93983c2b2549d9c382e9c84252505f32fdfd05d6d0d35db9e98888fb46a9b17270509b933f6e012cac
7
- data.tar.gz: bc88bea336a11ce1b277f6c270670e438aa9d841ca6a2669122afd0b92107c379f54d55a44603742f4de3943e119a7721672e3a85125876f22f61da480e2a819
6
+ metadata.gz: 2efa961d309f5b2c729adb7f8c2c4b8a576195566fd27605401e2c9882bdedfdcf15a7562b47bf0a65e96ef5ffc0788ed358c29353abab9169440f33787278dd
7
+ data.tar.gz: 566eb78c672a2bec211480ac09651dbdf458f7674983dbae0b4079691d553410ca71dfa9f4f7753a91a9cae1d59e13b5e55b7a18bdc37ab707690ad56a0d232f
@@ -1,5 +1,9 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.0.4 2021-01-22
4
+
5
+ - First fully functional release
6
+
3
7
  ## 1.0.0 2021-01-21
4
8
 
5
9
  - Initial release
data/README.md CHANGED
@@ -6,4 +6,72 @@
6
6
 
7
7
  ## Description
8
8
 
9
- Fun little project about labyrinth solving.
9
+ Fun little project about labyrinth solving inspired in mice that find cheese in a maze.
10
+
11
+ It exposes some classes to create a labyrinth and then find the path to the cheese.
12
+
13
+ Be advised: **It does not support labyrinths with circular paths and if you try to solve one of these, it will result in an infinite loop**.
14
+
15
+ That being said, I plan to support that kind of labyrinths soon.
16
+
17
+ ## Usage
18
+
19
+ ```
20
+ gem install subparry_labyrinth_solver
21
+ ```
22
+
23
+ ```ruby
24
+ require 'subparry_labyrinth_solver'
25
+
26
+ # First define labyrinth data as a 2 dimensional array where
27
+ # each square is represented by a hash with :up, :down, :left and :right
28
+ # as keys and an optional key :cheese representing the "goal" square.
29
+ # A value of true for a direction represents an open path, and false
30
+ # represents a wall.
31
+
32
+ data = [
33
+ [ # The first row
34
+ { up: false, right: false, left: false, down: true },
35
+ { up: false, right: false, left: false, down: true, cheese: true },
36
+ ],
37
+ [ # The second row
38
+ { up: true, down: false, right: true, left: false },
39
+ { up: true, down: false, right: false, left: true }
40
+ ]
41
+ ]
42
+
43
+ # This data represents this maze:
44
+ # ___ ___
45
+ # | | 🧀|
46
+ # | | |
47
+ # | |
48
+ # |_______|
49
+
50
+ # Then initialize the labyrinth:
51
+ lab = LabyrinthSolver::Labyrinth.new(data)
52
+
53
+ # Then initialize the solver:
54
+ solver = LabyrinthSolver::Solver.new(lab)
55
+
56
+ # And call solve on the instance. This call will trigger
57
+ # the cheese-finding loop and record the right path.
58
+ solver.solve
59
+
60
+ # Confirm that cheese was found:
61
+ solver.cheese? # => true
62
+
63
+ # Retrieve the path:
64
+ solver.path # => [:down, :right, :up]
65
+
66
+ # Get the coordinates of the cheese:
67
+ solver.position # => <struct x: 1, y: 0>
68
+
69
+ # Note that the coordinates are like image coordinates where top-left
70
+ # corner is x: 0, y: 0 and bottom-right is x: width, y: length
71
+ ```
72
+
73
+ ## Pending
74
+
75
+ - Support labyrinths with circular paths
76
+ - Create a labyrinth maker class
77
+ - Visual representation of labyrinths
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require File.expand_path('lib/subparry_labyrinth_solver/version', __dir__)
3
+ lib = File.expand_path('../lib', __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'subparry_labyrinth_solver/version'
4
6
 
5
7
  Gem::Specification.new do |spec|
6
8
  spec.name = 'subparry_labyrinth_solver'
@@ -8,7 +10,7 @@ Gem::Specification.new do |spec|
8
10
  spec.authors = ['Adrian Parry']
9
11
  spec.email = ['subparry@gmail.com']
10
12
  spec.summary = 'An exercise for gem creation based on solving a labyrinth'
11
- spec.description = 'This gem allows to find path for exiting a labyrinth'
13
+ spec.description = 'This gem allows to find path to cheese in a labyrinth'
12
14
  spec.homepage = 'https://github.com/subparry/subparry-labyrinth-solver'
13
15
  spec.license = 'MIT'
14
16
  spec.platform = Gem::Platform::RUBY
@@ -23,8 +25,8 @@ Gem::Specification.new do |spec|
23
25
  'lib/**/*.rb',
24
26
  'labyrinth.gemspec'
25
27
  ]
26
- spec.extra_rdoc_files = ['README.md']
27
-
28
+ spec.extra_rdoc_files = ['README.md']
29
+
28
30
  spec.add_development_dependency 'codecov', '~> 0.1'
29
31
  spec.add_development_dependency 'rspec', '~> 3.0'
30
32
  spec.add_development_dependency 'rubocop', '~> 1.8'
@@ -0,0 +1,8 @@
1
+ require 'subparry_labyrinth_solver/node'
2
+ require 'subparry_labyrinth_solver/labyrinth'
3
+ require 'subparry_labyrinth_solver/solver'
4
+ module LabyrinthSolver
5
+ class MissingPathsError < ArgumentError; end
6
+ class InvalidMoveError < RuntimeError; end
7
+ class MissingCheeseError < ArgumentError; end
8
+ end
@@ -2,47 +2,49 @@
2
2
 
3
3
  require 'forwardable'
4
4
 
5
- Point = Struct.new(:x, :y)
6
- # Labyrinth class in charge of keeping track of all nodes and performing movements
7
- class Labyrinth
8
- attr_reader :height, :width, :position
5
+ module LabyrinthSolver
6
+ Point = Struct.new(:x, :y)
7
+ # Labyrinth class in charge of keeping track of all nodes and performing movements
8
+ class Labyrinth
9
+ attr_reader :height, :width, :position
9
10
 
10
- extend Forwardable
11
+ extend Forwardable
11
12
 
12
- def_delegators :current_node, :open?, :cheese?, :close
13
+ def_delegators :current_node, :open?, :cheese?, :close
13
14
 
14
- def self.validate_data data
15
- raise ArgumentError unless data.respond_to?(:each) && data.first.respond_to?(:each)
16
- raise MissingCheeseError unless data.any? { |rows| rows.any? {|paths| paths[:cheese]} }
17
- end
15
+ def self.validate_data data
16
+ raise ArgumentError unless data.respond_to?(:each) && data.first.respond_to?(:each)
17
+ raise MissingCheeseError unless data.any? { |rows| rows.any? {|paths| paths[:cheese]} }
18
+ end
18
19
 
19
- def initialize(data)
20
- Labyrinth.validate_data data
20
+ def initialize(data)
21
+ Labyrinth.validate_data data
21
22
 
22
- @height = data.size
23
- @width = data.first.size
24
- @position = Point.new(0, 0)
25
- @nodes = data.collect { |row| row.collect { |cell| Node.new(cell) } }
26
- end
23
+ @height = data.size
24
+ @width = data.first.size
25
+ @position = Point.new(0, 0)
26
+ @nodes = data.collect { |row| row.collect { |cell| Node.new(cell) } }
27
+ end
27
28
 
28
- def go direction
29
- raise InvalidMoveError, "Attempted to move #{direction}" unless open? direction
30
-
31
- case direction
32
- when :up
33
- @position.y -= 1
34
- when :down
35
- @position.y += 1
36
- when :left
37
- @position.x -= 1
38
- when :right
39
- @position.x += 1
29
+ def go direction
30
+ raise InvalidMoveError, "Attempted to move #{direction}" unless open? direction
31
+
32
+ case direction
33
+ when :up
34
+ @position.y -= 1
35
+ when :down
36
+ @position.y += 1
37
+ when :left
38
+ @position.x -= 1
39
+ when :right
40
+ @position.x += 1
41
+ end
40
42
  end
41
- end
42
43
 
43
- private
44
+ private
44
45
 
45
- def current_node
46
- @nodes[@position.y][@position.x]
46
+ def current_node
47
+ @nodes[@position.y][@position.x]
48
+ end
47
49
  end
48
- end
50
+ end
@@ -1,23 +1,25 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Class to represent a single labyrinth square or node
4
- class Node
5
- def initialize(paths)
6
- raise MissingPathsError if paths[:up].nil? || paths[:down].nil? || paths[:left].nil? || paths[:right].nil?
4
+ module LabyrinthSolver
5
+ class Node
6
+ def initialize(paths)
7
+ raise MissingPathsError if paths[:up].nil? || paths[:down].nil? || paths[:left].nil? || paths[:right].nil?
7
8
 
8
- @paths = paths
9
- @cheese = paths[:cheese] || false
10
- end
9
+ @paths = paths
10
+ @cheese = paths[:cheese] || false
11
+ end
11
12
 
12
- def open? direction
13
- @paths[direction]
14
- end
13
+ def open? direction
14
+ @paths[direction]
15
+ end
15
16
 
16
- def cheese?
17
- @cheese
18
- end
17
+ def cheese?
18
+ @cheese
19
+ end
19
20
 
20
- def close direction
21
- @paths[direction] = false
21
+ def close direction
22
+ @paths[direction] = false
23
+ end
22
24
  end
23
- end
25
+ end
@@ -1,41 +1,42 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'forwardable'
4
+ module LabyrinthSolver
5
+ # Takes a labyrinth and attempts to solve it saving the path taken
6
+ class Solver
7
+ attr_reader :path
4
8
 
5
- # Takes a labyrinth and attempts to solve it saving the path taken
6
- class Solver
7
- attr_reader :path
9
+ extend Forwardable
8
10
 
9
- extend Forwardable
11
+ OPPOSITE_DIRECTIONS = { up: :down, right: :left, down: :up, left: :right }.freeze
10
12
 
11
- OPPOSITE_DIRECTIONS = { up: :down, right: :left, down: :up, left: :right }.freeze
13
+ def_delegators :@labyrinth, :position, :cheese?, :go, :close
12
14
 
13
- def_delegators :@labyrinth, :position, :cheese?, :go, :close
15
+ def initialize labyrinth
16
+ raise ArgumentError unless labyrinth.instance_of? Labyrinth
14
17
 
15
- def initialize labyrinth
16
- raise ArgumentError unless labyrinth.instance_of? Labyrinth
18
+ @labyrinth = labyrinth
19
+ @path = []
20
+ end
17
21
 
18
- @labyrinth = labyrinth
19
- @path = []
20
- end
21
-
22
- def go_next
23
- next_dir = OPPOSITE_DIRECTIONS.find { |dir, opp| @labyrinth.open?(dir) && opp != @path.last }
24
- return dead_end unless next_dir
22
+ def go_next
23
+ next_dir = OPPOSITE_DIRECTIONS.find { |dir, opp| @labyrinth.open?(dir) && opp != @path.last }
24
+ return dead_end unless next_dir
25
25
 
26
- go(next_dir.first)
27
- @path.push(next_dir.first)
28
- end
26
+ go(next_dir.first)
27
+ @path.push(next_dir.first)
28
+ end
29
29
 
30
- def solve
31
- go_next until cheese?
32
- end
30
+ def solve
31
+ go_next until cheese?
32
+ end
33
33
 
34
- private
35
-
36
- def dead_end
37
- to_close = path.pop
38
- go(OPPOSITE_DIRECTIONS[to_close])
39
- close(to_close)
34
+ private
35
+
36
+ def dead_end
37
+ to_close = path.pop
38
+ go(OPPOSITE_DIRECTIONS[to_close])
39
+ close(to_close)
40
+ end
40
41
  end
41
- end
42
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module LabyrinthSolver
4
- VERSION = '1.0.2'
4
+ VERSION = '1.0.4'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: subparry_labyrinth_solver
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.2
4
+ version: 1.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adrian Parry
@@ -94,7 +94,7 @@ dependencies:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0.16'
97
- description: This gem allows to find path for exiting a labyrinth
97
+ description: This gem allows to find path to cheese in a labyrinth
98
98
  email:
99
99
  - subparry@gmail.com
100
100
  executables: []
@@ -109,7 +109,6 @@ files:
109
109
  - Rakefile
110
110
  - labyrinth.gemspec
111
111
  - lib/subparry_labyrinth_solver.rb
112
- - lib/subparry_labyrinth_solver/exceptions.rb
113
112
  - lib/subparry_labyrinth_solver/labyrinth.rb
114
113
  - lib/subparry_labyrinth_solver/node.rb
115
114
  - lib/subparry_labyrinth_solver/solver.rb
@@ -1,3 +0,0 @@
1
- class MissingPathsError < ArgumentError; end
2
- class InvalidMoveError < RuntimeError; end
3
- class MissingCheeseError < ArgumentError; end