nasa_rovers 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +2 -0
- data/.ruby-version +1 -0
- data/.travis.yml +7 -0
- data/Gemfile +4 -0
- data/OBJECTIVES.md +41 -0
- data/README.md +81 -0
- data/Rakefile +10 -0
- data/bin/console +14 -0
- data/bin/nasa_rovers +9 -0
- data/bin/setup +8 -0
- data/lib/nasa_rovers.rb +11 -0
- data/lib/nasa_rovers/cli.rb +41 -0
- data/lib/nasa_rovers/coord.rb +33 -0
- data/lib/nasa_rovers/plateau.rb +24 -0
- data/lib/nasa_rovers/position.rb +32 -0
- data/lib/nasa_rovers/rover.rb +84 -0
- data/lib/nasa_rovers/version.rb +3 -0
- data/nasa_data.txt +5 -0
- data/nasa_rovers.gemspec +21 -0
- metadata +105 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: bde9963aec22cee7e62520420adf36418152e750fcae772b460ffb66f366a0b5
|
4
|
+
data.tar.gz: ceb0fd9641e1d3fd48b8eff336033281bbc1681077894827439fbc4e46ee29f4
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 112a7da8ac2e1a06b0db42aa6af6188ab4b2bc58b4ea55bd14f9aad5bb4199c730462644304ce87c36a24685d1be6e08f1848587c520ccace279bd95b1395bb7
|
7
|
+
data.tar.gz: 73687811157685f0bf75e0c78575c304779b6f369a348706fe5893d329d7ec0d4c673eeb14eddeae3368d4eb31e2baee70b0b92c7f1f8a0cf4c814613f0ec32f
|
data/.gitignore
ADDED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.5.3
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/OBJECTIVES.md
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
## Table of Contents
|
2
|
+
* [Summary](#summary)
|
3
|
+
|
4
|
+
## Summary
|
5
|
+
A squad of robotic rovers are to be landed by NASA on a plateau on Mars. This plateau, which is curiously rectangular, must be navigated by the rovers so that their on-board cameras can get a complete view of the surrounding terrain to send back to Earth.
|
6
|
+
A rover's position and location is represented by a combination of x and y coordinates and a letter representing one of the four cardinal compass points. The plateau is divided up into a grid to simplify navigation.
|
7
|
+
|
8
|
+
An example position might be `0, 0, N`, which means the rover is in the bottom left corner and facing North.
|
9
|
+
|
10
|
+
In order to control a rover, NASA sends a simple string of letters. The possible letters are `L`, `R` and `M`. `L` and `R` makes the rover spin 90 degrees left or right respectively, without moving from its current spot. `M` means move forward one grid point, and maintain the same heading.
|
11
|
+
|
12
|
+
Assume that the square directly North from (x, y) is (x, y+1).
|
13
|
+
|
14
|
+
### Input
|
15
|
+
The first line of input is the upper-right coordinates of the plateau, the lower-left coordinates are assumed to be `0,0`.
|
16
|
+
|
17
|
+
The rest of the input is information pertaining to the rovers that have been deployed. Each rover has two lines of input. The first line gives the rover's position, and the second line is a series of instructions telling the rover how to explore the plateau.
|
18
|
+
|
19
|
+
The position is made up of two integers and a letter separated by spaces, corresponding to the x and y co-ordinates and the rover's orientation.
|
20
|
+
|
21
|
+
Each rover will be finished sequentially, which means that the second rover won't start to move until the first one has finished moving.
|
22
|
+
|
23
|
+
### Output
|
24
|
+
The output for each rover should be its final co-ordinates and heading.
|
25
|
+
|
26
|
+
### Input and Output
|
27
|
+
|
28
|
+
#### Test Input
|
29
|
+
```
|
30
|
+
5 5
|
31
|
+
1 2 N
|
32
|
+
LMLMLMLMM
|
33
|
+
3 3 E
|
34
|
+
MMRMMRMRRM
|
35
|
+
```
|
36
|
+
|
37
|
+
#### Expected Output
|
38
|
+
```
|
39
|
+
1 3 N
|
40
|
+
5 1 E
|
41
|
+
```
|
data/README.md
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
## Table of Contents
|
2
|
+
* [Scope](#scope)
|
3
|
+
* [Design](#design)
|
4
|
+
* [Footprint](#footprint)
|
5
|
+
* [SRP](#srp)
|
6
|
+
* [Test](#test)
|
7
|
+
* [Usage](#usage)
|
8
|
+
* [Library](#library)
|
9
|
+
* [CLI](#cli)
|
10
|
+
|
11
|
+
## Scope
|
12
|
+
This gem is the Ruby implementation of the for the [NASA rovers](https://github.com/costajob/nasa_rovers/blob/master/OBJECTIVES.md) code kata.
|
13
|
+
|
14
|
+
## Design
|
15
|
+
|
16
|
+
### Footprint
|
17
|
+
The code keeps a minimal footprint, relying on standard library only and reducing it to its minimum (i.e. `optparse` was overkill for the simple CLI interface).
|
18
|
+
|
19
|
+
### SRP
|
20
|
+
The code design follows the single responsibility principle by using a dedicated class for any specific task.
|
21
|
+
|
22
|
+
### Test
|
23
|
+
The code is covered by fast, isolated unit testing, implemented by `minitest` spec (a standard, faster and as same as powerful alternative to `rspec`).
|
24
|
+
To run tests just execute rake:
|
25
|
+
|
26
|
+
```shell
|
27
|
+
bundle exec rake
|
28
|
+
Run options: --seed 4303
|
29
|
+
|
30
|
+
# Running:
|
31
|
+
|
32
|
+
.....................
|
33
|
+
|
34
|
+
Finished in 0.004475s, 4692.7374 runs/s, 7374.3017 assertions/s.
|
35
|
+
```
|
36
|
+
|
37
|
+
## Usage
|
38
|
+
|
39
|
+
### Library
|
40
|
+
Just execute the `bundle console` command and pass an array of instructions to the `Rover.instruct` method:
|
41
|
+
|
42
|
+
```ruby
|
43
|
+
nasa_data = ["5 5", "1 2 N", "LMLMLMLMM", "3 3 E", "MMRMMRMRRM"]
|
44
|
+
puts NasaRovers::Rover.instruct(nasa_data)
|
45
|
+
#1 3 N
|
46
|
+
#5 1 E
|
47
|
+
#=> nil
|
48
|
+
```
|
49
|
+
|
50
|
+
### CLI
|
51
|
+
The library provides a CLI interface via the `nasa_rovers` command from the terminal.
|
52
|
+
|
53
|
+
#### Help
|
54
|
+
You can print CLI help by:
|
55
|
+
|
56
|
+
```shell
|
57
|
+
$ ./bin/nasa_rovers -h
|
58
|
+
Usage: nasa_rovers ./nasa_data.txt
|
59
|
+
-h --help Print this help
|
60
|
+
<path-to-file> Instruct rovers with NASA data
|
61
|
+
```
|
62
|
+
|
63
|
+
#### Input
|
64
|
+
The program accepts as input a file containing the NASA data (for more info check ``SUMMARY.md`)
|
65
|
+
|
66
|
+
```txt
|
67
|
+
# ./nasa_data.txt
|
68
|
+
5 5
|
69
|
+
1 2 N
|
70
|
+
LMLMLMLMM
|
71
|
+
3 3 E
|
72
|
+
MMRMMRMRRM
|
73
|
+
```
|
74
|
+
|
75
|
+
Just pass the file path to the program:
|
76
|
+
|
77
|
+
```shell
|
78
|
+
$ ./bin/nasa_rovers ./nasa_data.txt
|
79
|
+
1 3 N
|
80
|
+
5 1 E
|
81
|
+
```
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "nasa_rovers"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/nasa_rovers
ADDED
data/bin/setup
ADDED
data/lib/nasa_rovers.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
require "nasa_rovers/rover"
|
2
|
+
|
3
|
+
module NasaRovers
|
4
|
+
class CLI
|
5
|
+
HELP_FLAGS = %w[-h --help]
|
6
|
+
COL_WIDTH = 23
|
7
|
+
|
8
|
+
def initialize(input, pipe=STDOUT, rover_class=Rover)
|
9
|
+
@input = input
|
10
|
+
@pipe = pipe
|
11
|
+
@rover = rover_class
|
12
|
+
end
|
13
|
+
|
14
|
+
def call
|
15
|
+
@pipe.puts output
|
16
|
+
end
|
17
|
+
|
18
|
+
private def output
|
19
|
+
return help if help?
|
20
|
+
return unless file?
|
21
|
+
data = File.readlines(@input).map(&:strip)
|
22
|
+
@rover.instruct(data)
|
23
|
+
end
|
24
|
+
|
25
|
+
private def file?
|
26
|
+
File.file?(File.expand_path(@input))
|
27
|
+
end
|
28
|
+
|
29
|
+
private def help?
|
30
|
+
HELP_FLAGS.include?(@input)
|
31
|
+
end
|
32
|
+
|
33
|
+
private def help
|
34
|
+
[].tap do |h|
|
35
|
+
h << %q{Usage: nasa_rovers ~/nasa_data.txt}
|
36
|
+
h << " %-#{COL_WIDTH}s Print this help" % "-h --help"
|
37
|
+
h << " %-#{COL_WIDTH}s Instruct rovers with NASA data" % "<path-to-file>"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module NasaRovers
|
2
|
+
class Coord
|
3
|
+
def self.origin
|
4
|
+
@origin ||= new(0, 0)
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.factory(data)
|
8
|
+
new(*data.split(" "))
|
9
|
+
end
|
10
|
+
|
11
|
+
attr_accessor :x, :y
|
12
|
+
|
13
|
+
def initialize(x, y)
|
14
|
+
@x, @y = x.to_i, y.to_i
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_s
|
18
|
+
"#{x} #{y}"
|
19
|
+
end
|
20
|
+
|
21
|
+
def >=(other)
|
22
|
+
x >= other.x && y >= other.y
|
23
|
+
end
|
24
|
+
|
25
|
+
def <=(other)
|
26
|
+
x <= other.x && y <= other.y
|
27
|
+
end
|
28
|
+
|
29
|
+
def ==(other)
|
30
|
+
x == other.x && y == other.y
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require "nasa_rovers/coord"
|
2
|
+
|
3
|
+
module NasaRovers
|
4
|
+
class Plateau
|
5
|
+
def self.factory(data, coord_class=Coord)
|
6
|
+
new(*data.split(" "), coord_class)
|
7
|
+
end
|
8
|
+
|
9
|
+
attr_reader :bot_lt, :top_rt
|
10
|
+
|
11
|
+
def initialize(x, y, coord_class=Coord)
|
12
|
+
@bot_lt = coord_class.origin
|
13
|
+
@top_rt = coord_class.new(x, y)
|
14
|
+
end
|
15
|
+
|
16
|
+
def include?(coord)
|
17
|
+
coord >= bot_lt && coord <= top_rt
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_s
|
21
|
+
"#{bot_lt} - #{top_rt}"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require "nasa_rovers/coord"
|
2
|
+
|
3
|
+
module NasaRovers
|
4
|
+
class Position
|
5
|
+
class CardinalError < StandardError; end
|
6
|
+
|
7
|
+
def self.factory(data)
|
8
|
+
new(*data.split(" "))
|
9
|
+
end
|
10
|
+
|
11
|
+
attr_reader :coord
|
12
|
+
attr_accessor :cardinal
|
13
|
+
|
14
|
+
def initialize(x, y, cardinal, coord_class=Coord)
|
15
|
+
@coord = coord_class.new(x, y)
|
16
|
+
@cardinal = check(cardinal)
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_s
|
20
|
+
"#{coord} #{cardinal}"
|
21
|
+
end
|
22
|
+
|
23
|
+
def ==(other)
|
24
|
+
coord == other.coord && cardinal == other.cardinal
|
25
|
+
end
|
26
|
+
|
27
|
+
private def check(cardinal)
|
28
|
+
return cardinal if CARDINALS.include?(cardinal)
|
29
|
+
fail CardinalError.new("#{cardinal} is not a valid cardinal point")
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require "forwardable"
|
2
|
+
require "nasa_rovers/plateau"
|
3
|
+
require "nasa_rovers/position"
|
4
|
+
|
5
|
+
module NasaRovers
|
6
|
+
class Rover
|
7
|
+
extend Forwardable
|
8
|
+
|
9
|
+
MAPPING = {
|
10
|
+
M: :move,
|
11
|
+
L: :left,
|
12
|
+
R: :right
|
13
|
+
}
|
14
|
+
|
15
|
+
INST_ROWS = 2
|
16
|
+
|
17
|
+
def self.factory(data, plateau, position_class=Position)
|
18
|
+
position = position_class.factory(data)
|
19
|
+
new(position, plateau)
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.instruct(data, plateau_class=Plateau)
|
23
|
+
plateau = plateau_class.factory(data.shift)
|
24
|
+
data.each_slice(INST_ROWS).reduce([]) do |rovers, rows|
|
25
|
+
position, instructions = rows
|
26
|
+
rover = factory(position, plateau)
|
27
|
+
rover.call(instructions)
|
28
|
+
rovers << rover
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def_delegators :@position, :cardinal, :coord, :to_s
|
33
|
+
|
34
|
+
attr_reader :plateau, :position
|
35
|
+
|
36
|
+
def initialize(position, plateau)
|
37
|
+
@position = position
|
38
|
+
@plateau = plateau
|
39
|
+
end
|
40
|
+
|
41
|
+
def call(data)
|
42
|
+
instructions(data).each do |inst|
|
43
|
+
action = MAPPING.fetch(inst) { :stay }
|
44
|
+
send(action)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
private def instructions(data)
|
49
|
+
data.split("").map(&:strip).map(&:to_sym)
|
50
|
+
end
|
51
|
+
|
52
|
+
private def left
|
53
|
+
position.cardinal = CARDINALS[cardinal_idx-1]
|
54
|
+
end
|
55
|
+
|
56
|
+
private def right
|
57
|
+
idx = CARDINALS[cardinal_idx+1] ? cardinal_idx+1 : 0
|
58
|
+
position.cardinal = CARDINALS[idx]
|
59
|
+
end
|
60
|
+
|
61
|
+
private def cardinal_idx
|
62
|
+
CARDINALS.index(cardinal)
|
63
|
+
end
|
64
|
+
|
65
|
+
private def move
|
66
|
+
case cardinal
|
67
|
+
when "N"
|
68
|
+
coord.y += 1
|
69
|
+
coord.y = plateau.top_rt.y unless plateau.include?(coord)
|
70
|
+
when "E"
|
71
|
+
coord.x += 1
|
72
|
+
coord.x = plateau.top_rt.x unless plateau.include?(coord)
|
73
|
+
when "S"
|
74
|
+
coord.y -= 1
|
75
|
+
coord.y = plateau.bot_lt.y unless plateau.include?(coord)
|
76
|
+
when "W"
|
77
|
+
coord.x -= 1
|
78
|
+
coord.x = plateau.bot_lt.x unless plateau.include?(coord)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
private def stay; end
|
83
|
+
end
|
84
|
+
end
|
data/nasa_rovers.gemspec
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require "nasa_rovers/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = "nasa_rovers"
|
8
|
+
s.version = NasaRovers::VERSION
|
9
|
+
s.authors = ["costajob"]
|
10
|
+
s.email = ["costajob@gmail.com"]
|
11
|
+
s.summary = "The Ruby implementation of the NASA rovers code kata."
|
12
|
+
s.homepage = "https://github.com/costajob/nasa_rovers"
|
13
|
+
s.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
14
|
+
s.bindir = "bin"
|
15
|
+
s.executables << "nasa_rovers"
|
16
|
+
s.require_paths = ["lib"]
|
17
|
+
s.required_ruby_version = ">= 2.3.1"
|
18
|
+
s.add_development_dependency "bundler", "~> 1.16"
|
19
|
+
s.add_development_dependency "rake", "~> 12.3"
|
20
|
+
s.add_development_dependency "minitest", "~> 5.1"
|
21
|
+
end
|
metadata
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: nasa_rovers
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- costajob
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-12-11 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.16'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.16'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '12.3'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '12.3'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: minitest
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '5.1'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '5.1'
|
55
|
+
description:
|
56
|
+
email:
|
57
|
+
- costajob@gmail.com
|
58
|
+
executables:
|
59
|
+
- nasa_rovers
|
60
|
+
extensions: []
|
61
|
+
extra_rdoc_files: []
|
62
|
+
files:
|
63
|
+
- ".gitignore"
|
64
|
+
- ".ruby-version"
|
65
|
+
- ".travis.yml"
|
66
|
+
- Gemfile
|
67
|
+
- OBJECTIVES.md
|
68
|
+
- README.md
|
69
|
+
- Rakefile
|
70
|
+
- bin/console
|
71
|
+
- bin/nasa_rovers
|
72
|
+
- bin/setup
|
73
|
+
- lib/nasa_rovers.rb
|
74
|
+
- lib/nasa_rovers/cli.rb
|
75
|
+
- lib/nasa_rovers/coord.rb
|
76
|
+
- lib/nasa_rovers/plateau.rb
|
77
|
+
- lib/nasa_rovers/position.rb
|
78
|
+
- lib/nasa_rovers/rover.rb
|
79
|
+
- lib/nasa_rovers/version.rb
|
80
|
+
- nasa_data.txt
|
81
|
+
- nasa_rovers.gemspec
|
82
|
+
homepage: https://github.com/costajob/nasa_rovers
|
83
|
+
licenses: []
|
84
|
+
metadata: {}
|
85
|
+
post_install_message:
|
86
|
+
rdoc_options: []
|
87
|
+
require_paths:
|
88
|
+
- lib
|
89
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
90
|
+
requirements:
|
91
|
+
- - ">="
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: 2.3.1
|
94
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
95
|
+
requirements:
|
96
|
+
- - ">="
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '0'
|
99
|
+
requirements: []
|
100
|
+
rubyforge_project:
|
101
|
+
rubygems_version: 2.7.6
|
102
|
+
signing_key:
|
103
|
+
specification_version: 4
|
104
|
+
summary: The Ruby implementation of the NASA rovers code kata.
|
105
|
+
test_files: []
|