subparry_labyrinth_solver 1.0.2 → 1.0.4

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 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