mazemap 0.0.2

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