mazemap 0.0.2

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 1de2a8d8c405234dd72965b2791be516d8a29624
4
+ data.tar.gz: bbcee69ecb9a45efe837cfc08eb6ab4fb1144704
5
+ SHA512:
6
+ metadata.gz: '0978d9f462c4aacab6d8cb61fdc1413f1edd8014a9b9d6dc0be1957aff14a8d875c7169d1e93165ceccbe341f624d72b3cd122c9ad2c759fb433947ef1ecbeb2'
7
+ data.tar.gz: dcad932c2f9910bbc4703e54846f507d5e37f8b9c07b6368e190eeebf943bfa74037bedf63deb60d37b0777c269a6974a960afc4dd1e5b25b8f058552f79759a
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.rpsec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in my_gem.gemspec
4
+ gemspec
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Evgeniy
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,46 @@
1
+ ## Mazemap Pathfinder
2
+ Mazemap allows you to search for a shortest path in the given 2D map(check tmp/maze.txt for examples)
3
+
4
+ Mazemap has built-in command line tool
5
+ So after the gem installation you can just type
6
+ `bundle exec mazemap maze.txt`
7
+ to execute a search
8
+
9
+ #### Usage
10
+ Gemfile
11
+ `gem 'mazemap', github: 'leafmind/mazemap'`
12
+
13
+ `bundle install`
14
+
15
+ In your code:
16
+ `Mazemap.read_and_search(filename)`
17
+
18
+ Also you can use mazemap command line tool:
19
+ `bundle exec mazemap maze.txt`
20
+
21
+ #### Maze file format example
22
+
23
+ ```
24
+ ******************************************
25
+ * ****** *** *
26
+ * *** *** ****** * B *** *
27
+ * *** *** ****** *** *
28
+ * *** ***** *** *
29
+ * ********* ***** *** *
30
+ * ******* **** *** *** *
31
+ * ****** *
32
+ * *** **** ********** *
33
+ * *** *********** *
34
+ * ******* ************ *
35
+ * ******* **** *
36
+ * A **** ******
37
+ ******************************************
38
+ ```
39
+
40
+
41
+ Known issues on MAC OS X
42
+ https://github.com/SciRuby/nmatrix/issues/426
43
+
44
+ Workaround
45
+ https://github.com/SciRuby/nmatrix/issues/426#issuecomment-218122512
46
+
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require 'mazemap'
5
+
6
+ filename = ARGV[0]
7
+
8
+ if filename
9
+ puts Mazemap.read_and_search(filename).inspect
10
+ else
11
+ puts <<-EOF
12
+ Please specify input file as command line parameter
13
+ USAGE: bundle exec mazemap /path/to/your/file
14
+ File should contain maze in described format(see tmp/maze.txt)
15
+ EOF
16
+ end
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,22 @@
1
+ require 'nmatrix'
2
+ require 'mazemap/graph'
3
+ require 'mazemap/pathfinder'
4
+ require 'mazemap/version'
5
+
6
+ # Tries to find the shortest path
7
+ #
8
+ # @author Evgenii Shevchenko
9
+ # @since 0.0.1
10
+ module Mazemap
11
+ # Search for a shortest paths
12
+ #
13
+ # @example Run search
14
+ # >> Mazemap.read_and_search(filename)
15
+ # => [[6, 11], [7, 11], [8, 11], [9, 11], [10, 11]]
16
+ def read_and_search(filename)
17
+ pathfinder = Pathfinder.new(filename)
18
+ pathfinder.solution
19
+ end
20
+
21
+ module_function :read_and_search
22
+ end
@@ -0,0 +1,104 @@
1
+ module Mazemap
2
+ # Graph object class
3
+ #
4
+ # @author Evgenii Shevchenko
5
+ # @!attribute [r] graph
6
+ # @return [NMatrix] graph map matrix
7
+ # @!attribute [r] queue
8
+ # @return [Queue] progress queue
9
+ # @!attribute [r] rows
10
+ # @return [Integer] number of the rows
11
+ # @!attribute [r] cols
12
+ # @return [Integer] number of the cols
13
+ class Graph
14
+ attr_reader :graph
15
+ attr_reader :queue
16
+ attr_reader :rows
17
+ attr_reader :cols
18
+
19
+ INF = Float::INFINITY
20
+ BLANK = -Float::INFINITY
21
+ VISITED = Float::MAX
22
+ START = 1
23
+ FINISH = 2
24
+
25
+ # Initializes Graph object, sets rows and cols, graph map
26
+ #
27
+ # @param n [Integer] number of rows
28
+ # @param m [Integer] number of columns
29
+ # @param graph_map [Array] prepared vector of the graph map
30
+ def initialize(n, m, graph_map)
31
+ @rows, @cols = n, m
32
+ @graph = NMatrix.new([n, m], graph_map)
33
+ @queue = Queue.new
34
+ end
35
+
36
+ # Starts a search for the shortest path
37
+ #
38
+ # @param start [Array] start vertex coords
39
+ # @param finish [Array] finish vertex coords
40
+ def shortest_path(start, finish)
41
+ queue << [start, 0]
42
+ loop do
43
+ break if queue.empty?
44
+ vertex, d = queue.pop
45
+ graph[*vertex] = d
46
+ break if vertex == finish
47
+ enqueue_neighbours(*vertex, d + 1)
48
+ end
49
+ queue.clear
50
+ !blank?(finish) ? build_path(start, finish) : []
51
+ end
52
+
53
+ private
54
+
55
+ # Checks if vertex is blank
56
+ #
57
+ # @param vertex [Array] vertex coords
58
+ def blank?(vertex)
59
+ graph[*vertex] == BLANK
60
+ end
61
+
62
+ # Builds the shortest path from the processed graph
63
+ #
64
+ # @param start [Array] start vertex coords
65
+ # @param finish [Array] finish vertex coords
66
+ def build_path(start, finish)
67
+ path = [finish]
68
+ loop do
69
+ vertex = path.last
70
+ d = graph[*vertex]
71
+ neighbours = get_neighbours(*vertex)
72
+ next_vertex = neighbours.select{|n_vert| graph[*n_vert] == d - 1}.first
73
+ path << next_vertex if next_vertex
74
+ break if vertex == start
75
+ end
76
+ path
77
+ end
78
+
79
+ # Collects the neighbours of the given vertex
80
+ #
81
+ # @param n [Integer] row number of vertex
82
+ # @param m [Integer] column number of vertex
83
+ def get_neighbours(n, m)
84
+ [[n - 1, m],[n + 1, m],[n, m - 1],[n, m + 1]].select do |coords|
85
+ coords.first.between?(0, rows - 1) && coords.last.between?(0, cols - 1)
86
+ end
87
+ end
88
+
89
+ # Adds the neighbours of the given vertex to the queue and marks them
90
+ #
91
+ # @param n [Integer] row number of vertex
92
+ # @param m [Integer] column number of vertex
93
+ # @param d [Integer] distance mark of vertex
94
+ def enqueue_neighbours(n, m, d)
95
+ get_neighbours(n, m).each do |vertex|
96
+ if blank?(vertex)
97
+ graph[*vertex] = VISITED
98
+ queue << [vertex, d]
99
+ end
100
+ end
101
+ end
102
+
103
+ end
104
+ end
@@ -0,0 +1,78 @@
1
+ module Mazemap
2
+ # Pathfinder object class
3
+ #
4
+ # @author Evgenii Shevchenko
5
+ # @!attribute [r] lines
6
+ # @return [Array] maze representation
7
+ # @!attribute [r] rows
8
+ # @return [Integer] number of the rows
9
+ # @!attribute [r] cols
10
+ # @return [Integer] number of the cols
11
+ # @!attribute [r] start
12
+ # @return [Integer] start vertex coords
13
+ # @!attribute [r] finish
14
+ # @return [Integer] finish vertex coords
15
+ class Pathfinder
16
+ attr_reader :lines
17
+ attr_reader :rows
18
+ attr_reader :cols
19
+ attr_reader :start
20
+ attr_reader :finish
21
+
22
+ VERTEX_VALUES = {
23
+ ' ' => Graph::BLANK,
24
+ '*' => Graph::INF,
25
+ 'A' => Graph::START,
26
+ 'B' => Graph::FINISH
27
+ }
28
+
29
+ # Initializes Pathfinder, sets @lines, @rows and @cols
30
+ #
31
+ # @param filename [String] path to file with maze
32
+ def initialize(filename)
33
+ if filename
34
+ @lines = IO.readlines(filename).map(&:chomp)
35
+ @rows = lines.length
36
+ @cols = lines.first.length
37
+ end
38
+ end
39
+
40
+ # Starts a search for the shortest path
41
+ def solution
42
+ graph_map = parse_graph_map.flatten
43
+ set_route(graph_map)
44
+ graph = Graph.new(rows, cols, graph_map)
45
+ graph.shortest_path(start, finish).map(&:reverse).reverse
46
+ end
47
+
48
+ private
49
+
50
+ # Sets start and finish vertex coords
51
+ #
52
+ # @param graph_map [Array] flatterned graph map
53
+ def set_route(graph_map)
54
+ start_element = graph_map.index(Graph::START)
55
+ finish_element = graph_map.index(Graph::FINISH)
56
+ graph_map[start_element] = Graph::BLANK
57
+ graph_map[finish_element] = Graph::BLANK
58
+ @start = [start_element / cols, start_element % cols]
59
+ @finish = [finish_element / cols, finish_element % cols]
60
+ end
61
+
62
+ # Converts letter according to maze format
63
+ #
64
+ # @param letter [String] letter to convert
65
+ def convert_letter(letter)
66
+ VERTEX_VALUES[letter] || letter
67
+ end
68
+
69
+ # Parses the maze map and converts it to the internal format
70
+ def parse_graph_map
71
+ lines.map do |line|
72
+ line.split('').map do |letter|
73
+ convert_letter(letter)
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,3 @@
1
+ module Mazemap
2
+ VERSION = '0.0.2'
3
+ end
@@ -0,0 +1,37 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'mazemap/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.authors = ["Evgenii Shevchenko"]
8
+
9
+ spec.name = 'mazemap'
10
+ spec.version = '0.0.1'
11
+ spec.date = '2016-12-16'
12
+ spec.summary = 'MazeMap Graph Pathfinder'
13
+ spec.description = 'Runs Wavefront algorithm to find the shortest path from A to B'
14
+ spec.homepage = 'https://github.com/leafmind/mazemap'
15
+
16
+ spec.email = 'leafmind@gmail.com'
17
+
18
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
19
+ f.match(%r{^(test|spec|features)/})
20
+ end
21
+
22
+ spec.executables = spec.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
23
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
24
+ spec.require_paths = ["lib"]
25
+ spec.version = Mazemap::VERSION
26
+
27
+ spec.license = 'MIT'
28
+
29
+ spec.add_dependency 'nmatrix'
30
+
31
+ spec.add_development_dependency "bundler", "~> 1.13"
32
+ spec.add_development_dependency "rake", "~> 11.3"
33
+ spec.add_development_dependency "rspec", "~> 3.5"
34
+ spec.add_development_dependency "yard", "~> 0.9"
35
+ spec.add_development_dependency "shoulda-matchers"
36
+ spec.add_development_dependency "awesome_print"
37
+ end
metadata ADDED
@@ -0,0 +1,156 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mazemap
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Evgenii Shevchenko
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-12-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: nmatrix
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.13'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.13'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '11.3'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '11.3'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.5'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.5'
69
+ - !ruby/object:Gem::Dependency
70
+ name: yard
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0.9'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0.9'
83
+ - !ruby/object:Gem::Dependency
84
+ name: shoulda-matchers
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: awesome_print
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ description: Runs Wavefront algorithm to find the shortest path from A to B
112
+ email: leafmind@gmail.com
113
+ executables:
114
+ - mazemap
115
+ - setup
116
+ extensions: []
117
+ extra_rdoc_files: []
118
+ files:
119
+ - ".gitignore"
120
+ - ".rpsec"
121
+ - Gemfile
122
+ - LICENSE.txt
123
+ - README.md
124
+ - Rakefile
125
+ - bin/mazemap
126
+ - bin/setup
127
+ - lib/mazemap.rb
128
+ - lib/mazemap/graph.rb
129
+ - lib/mazemap/pathfinder.rb
130
+ - lib/mazemap/version.rb
131
+ - mazemap.gemspec
132
+ homepage: https://github.com/leafmind/mazemap
133
+ licenses:
134
+ - MIT
135
+ metadata: {}
136
+ post_install_message:
137
+ rdoc_options: []
138
+ require_paths:
139
+ - lib
140
+ required_ruby_version: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - ">="
143
+ - !ruby/object:Gem::Version
144
+ version: '0'
145
+ required_rubygems_version: !ruby/object:Gem::Requirement
146
+ requirements:
147
+ - - ">="
148
+ - !ruby/object:Gem::Version
149
+ version: '0'
150
+ requirements: []
151
+ rubyforge_project:
152
+ rubygems_version: 2.5.2
153
+ signing_key:
154
+ specification_version: 4
155
+ summary: MazeMap Graph Pathfinder
156
+ test_files: []