another_toy_robot 0.1.8 → 0.1.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +0 -10
- data/README.md +108 -22
- data/lib/toy_robot.rb +4 -14
- data/lib/toy_robot/arena.rb +4 -14
- data/lib/toy_robot/client.rb +5 -16
- data/lib/toy_robot/command.rb +11 -67
- data/lib/toy_robot/input.rb +38 -0
- data/lib/toy_robot/invalid_command.rb +7 -0
- data/lib/toy_robot/left_command.rb +7 -0
- data/lib/toy_robot/move_command.rb +7 -0
- data/lib/toy_robot/null_position.rb +5 -2
- data/lib/toy_robot/place_command.rb +40 -0
- data/lib/toy_robot/position.rb +12 -9
- data/lib/toy_robot/report_command.rb +7 -0
- data/lib/toy_robot/right_command.rb +7 -0
- data/lib/toy_robot/robot.rb +15 -13
- data/lib/toy_robot/version.rb +1 -1
- data/toy_robot.gemspec +7 -1
- metadata +80 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 43ea9ed6146a026f2e64bf8fb0c9190950f8ae76
|
4
|
+
data.tar.gz: ea3faa443089ea8a429f6f8305b5c3fcb7a99873
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 556f6c6f940b2079d8be8c87d7ac853541d1ed2aadc097f3a5ef665f2950289e4b64891ffe0f477110571edafa1998dfd4e8dbba53db875766a042566c6e6b1b
|
7
|
+
data.tar.gz: f1a887cfa16bdd63a2bd36429f43904db8bb0829e255b11a2296fbb357d231d06c6a9c0f4824b828d0c652670af2ff49334830597088a22a5b881074a3200279
|
data/Gemfile
CHANGED
@@ -1,14 +1,4 @@
|
|
1
1
|
source "https://rubygems.org"
|
2
2
|
|
3
|
-
gem "pry"
|
4
|
-
gem "rspec"
|
5
|
-
gem "rake"
|
6
|
-
gem "factory_girl", "~> 4.0"
|
7
|
-
|
8
|
-
group :test do
|
9
|
-
gem "simplecov", require: false
|
10
|
-
gem "codeclimate-test-reporter", "~> 1.0.0"
|
11
|
-
end
|
12
|
-
|
13
3
|
# Specify your gem's dependencies in toy_robot.gemspec
|
14
4
|
gemspec
|
data/README.md
CHANGED
@@ -4,21 +4,42 @@
|
|
4
4
|
[![Build Status](https://travis-ci.org/drzel/toy_robot.svg?branch=master)](https://travis-ci.org/drzel/toy_robot)
|
5
5
|
|
6
6
|
# Another Toy Robot Simulator
|
7
|
-
The application is a simulation of a toy robot moving on a 5 x 5 unit tabletop. It
|
8
|
-
is an example of a well tested, object oriented design, employing the command design
|
9
|
-
pattern.
|
7
|
+
The application is a simulation of a toy robot moving on a 5 x 5 unit tabletop. It is an example of a well tested, object oriented design, employing the command design pattern. It is commonly used as an code-test. See specifications below for the full text of the test.
|
10
8
|
|
11
|
-
###
|
12
|
-
|
9
|
+
### Environment
|
10
|
+
This application was developed on Ubuntu 16.10 x86_64. It requires Ruby 2.3 or later.
|
11
|
+
|
12
|
+
To check your version run:
|
13
|
+
```
|
14
|
+
$ ruby -v
|
15
|
+
```
|
16
|
+
|
17
|
+
Information on installing Ruby can be found at [Installing Ruby](https://www.ruby-lang.org/en/documentation/installation/).
|
13
18
|
|
14
19
|
### Installation
|
20
|
+
The latest release can be installed via RubyGems:
|
21
|
+
```
|
22
|
+
$ gem install another_toy_robot
|
23
|
+
```
|
24
|
+
|
25
|
+
Alternatively it can be built from source:
|
26
|
+
```
|
27
|
+
$ git clone https://github.com/drzel/toy_robot.git
|
28
|
+
$ cd toy_robot
|
29
|
+
$ bundle install
|
30
|
+
```
|
31
|
+
|
32
|
+
### Testing
|
33
|
+
The test suite is invoked with:
|
15
34
|
```
|
16
|
-
|
35
|
+
$ bundle exec rspec
|
17
36
|
```
|
18
37
|
|
38
|
+
Unit tests are written to [Sandi Metz' Unit Testing Minimalist](https://youtu.be/URSWYvyc42M) guidelines.
|
39
|
+
|
19
40
|
### Usage
|
20
41
|
```
|
21
|
-
toy_robot
|
42
|
+
$ toy_robot
|
22
43
|
```
|
23
44
|
|
24
45
|
This will present a prompt:
|
@@ -29,7 +50,7 @@ Input command:
|
|
29
50
|
Valid commands are:
|
30
51
|
|
31
52
|
| Command | Description
|
32
|
-
|
|
53
|
+
| --- | ---
|
33
54
|
| `place x,y,d` | Places robot at position `x`, `y`, facing cardinal direction `d`. E.g. `place 1,2,north`.
|
34
55
|
| `left` | Rotates robot 90° counter-clockwise.
|
35
56
|
| `right` | Rotates robot 90° clockwise.
|
@@ -39,16 +60,80 @@ Valid commands are:
|
|
39
60
|
|
40
61
|
Commands resulting in the robot moving to an out-of-bounds position (`x` or `y` being less than 0 or greater than 4) will be ignored.
|
41
62
|
|
63
|
+
### Design
|
64
|
+
The app implements:
|
65
|
+
- The [command pattern](https://en.wikipedia.org/wiki/Command_pattern)
|
66
|
+
- The [null-object pattern](https://en.wikipedia.org/wiki/Null_Object_pattern) (for positions)
|
67
|
+
- The [singleton pattern](https://en.wikipedia.org/wiki/Singleton_pattern) (for directions)
|
68
|
+
|
69
|
+
`toy_robot` is an executable in your load path. It is a Ruby script that calls the main function:
|
70
|
+
```
|
71
|
+
#!/usr/bin/env ruby
|
72
|
+
|
73
|
+
require "toy_robot"
|
74
|
+
ToyRobot.main
|
75
|
+
```
|
76
|
+
|
77
|
+
`ToyRobot#main` instantiates a new `Client`. The `Client` instantiates an `Arena` and `Robot` objects. The new `Robot` is initialised with `NullPosition` in the `Arena`.
|
78
|
+
|
79
|
+
- The main loop does the following:
|
80
|
+
- Requests user input
|
81
|
+
- Instantiates a new `Input` object
|
82
|
+
- Passes the new `Input` object to the client
|
83
|
+
|
84
|
+
The `Input` class contains methods to parse the user input and determine the correct `Command` class for the given command. E.g. `"move"` will resolve a the `MoveCommand` while `"derp"` will resolve `InvalidCommand`.
|
85
|
+
|
86
|
+
The client calls the `Input#new_command` method, passing the `@robot` as the target.
|
87
|
+
|
88
|
+
The `xCommand` object will parse any arguments provided and call the appropriate action on the `@robot`.
|
89
|
+
|
90
|
+
When receiving a `place` method the robot will check with its `@arena` to see if the position is `#inbounds` before assigning the new `Position` to itself.
|
91
|
+
|
92
|
+
When receiving `#left`, `#right` or `#move`, the robot will pass the request to its `@position` which will respond with the new position.
|
93
|
+
|
94
|
+
The `Robot` will then check with its `@arena` to see if the position is `#inbounds` before assigning the new position to itself.
|
95
|
+
|
96
|
+
When receiving a `#left`, `#right` or `#move` message the `NullPosition` will return itself.
|
97
|
+
|
98
|
+
When the `Robot` receives `#report` it prints its `@position` as a string.
|
99
|
+
|
100
|
+
This process continues until an `"exit"` command is received, breaking the loop.
|
101
|
+
|
102
|
+
### Considerations
|
103
|
+
Given the requirement for a command line interface to interact with the robot, I settled on the well established and widely used command pattern.
|
104
|
+
|
105
|
+
The `Input` wrapper allows new commands to be easily added. E.g. Creating a new file `lib/toy_robot/random_command.rb` and requiring it, would be all that is required for the application to accept the `"random"` command, and it would have access to an array of parameters. Validations can also be added by defining a `valid?` method on the command object. See the `lib/toy_robot/place_command.rb` for an example.
|
106
|
+
|
107
|
+
I'm particularly happy with the `Position` class and the `Direction` modules. Together as a unit they have absolutely no dependencies and could be easily reused with new features, new objects, or with changing specifications. It would be reasonably straight forward to add a second robot, or a third dimension.
|
108
|
+
|
109
|
+
Currently the `Robot` must be instantiated with an `Arena`. Originally, I had also employed the null object pattern for the `Arena` as well as the position, but as it turned out, with the current specification, there is no situation where a robot is not in an arena, so it was unneeded and removed, reducing overall complexity of the application.
|
110
|
+
|
111
|
+
As GINnFIN helpfully pointed out in the [Reddit discussion](https://www.reddit.com/r/ruby/comments/5fptz9/i_did_the_toy_robot_challenge_ive_tried_to_be/), the `Position` `#left` and `#right` methods do necessarily need to return a new instance of `Position`, and could instead mutate the current position in place. While this is true, there is a pleasing symmetry in each of the current `Position` methods returning a new instance of position that would would be lost if these were to be changed. I'm not entirely sure which is better, but have decided to keep the current implementation, as different behaviour for the `place` and `move` methods to the `left` and `right` methods may be unnecessarily increasing the conceptual complexity of the app.
|
112
|
+
|
113
|
+
### Licence
|
114
|
+
[MIT](https://tldrlegal.com/license/mit-license)
|
115
|
+
|
116
|
+
### Contributing
|
117
|
+
My goal is to continue to develop this application to use as an example for other developers who are learning Ruby and object oriented design and have attempted to ensure it is SOLID, DRY, OO and TDD.
|
118
|
+
|
119
|
+
If you have something to contribute, whether it be to report an bug, suggest a potential improvement or even ask a question, don't hesitate to log an issue.
|
120
|
+
|
121
|
+
Pull requests are also warmly welcomed.
|
122
|
+
|
123
|
+
### Links
|
124
|
+
- [another_toy_robot on RubyGems](https://rubygems.org/gems/another_toy_robot)
|
125
|
+
- [Discussion on Reddit](https://www.reddit.com/r/ruby/comments/5fptz9/i_did_the_toy_robot_challenge_ive_tried_to_be/?ref=share&ref_source=link)
|
126
|
+
|
42
127
|
## Specification
|
43
128
|
|
44
129
|
### Description
|
45
130
|
- The application is a simulation of a toy robot moving on a square tabletop,
|
46
|
-
of dimensions 5 units x 5 units.
|
131
|
+
of dimensions 5 units x 5 units.
|
47
132
|
- There are no other obstructions on the table surface.
|
48
133
|
- The robot is free to roam around the surface of the table, but must be
|
49
|
-
prevented from falling to destruction. Any movement that would result in the
|
50
|
-
robot falling from the table must be prevented, however further valid
|
51
|
-
movement commands must still be allowed.
|
134
|
+
prevented from falling to destruction. Any movement that would result in the
|
135
|
+
robot falling from the table must be prevented, however further valid
|
136
|
+
movement commands must still be allowed.
|
52
137
|
- Create an application that can read in commands of the following form:
|
53
138
|
|
54
139
|
```
|
@@ -60,20 +145,20 @@ REPORT
|
|
60
145
|
```
|
61
146
|
|
62
147
|
- PLACE will put the toy robot on the table in position X,Y and facing NORTH,
|
63
|
-
SOUTH, EAST or WEST.
|
148
|
+
SOUTH, EAST or WEST.
|
64
149
|
- The origin (0,0) can be considered to be the SOUTH WEST most corner.
|
65
150
|
- The first valid command to the robot is a PLACE command, after that, any
|
66
|
-
sequence of commands may be issued, in any order, including another PLACE
|
67
|
-
command. The application should discard all commands in the sequence until a
|
68
|
-
valid PLACE command has been executed.
|
151
|
+
sequence of commands may be issued, in any order, including another PLACE
|
152
|
+
command. The application should discard all commands in the sequence until a
|
153
|
+
valid PLACE command has been executed.
|
69
154
|
- MOVE will move the toy robot one unit forward in the direction it is currently
|
70
|
-
facing.
|
155
|
+
facing.
|
71
156
|
- LEFT and RIGHT will rotate the robot 90 degrees in the specified direction
|
72
|
-
without changing the position of the robot.
|
157
|
+
without changing the position of the robot.
|
73
158
|
- REPORT will announce the X,Y and F of the robot. This can be in any form, but
|
74
|
-
standard output is sufficient.
|
159
|
+
standard output is sufficient.
|
75
160
|
- A robot that is not on the table can choose the ignore the MOVE, LEFT, RIGHT
|
76
|
-
and REPORT commands.
|
161
|
+
and REPORT commands.
|
77
162
|
- Input can be from a file, or from standard input, as the developer chooses.
|
78
163
|
- Provide test data to exercise the application.
|
79
164
|
|
@@ -118,5 +203,6 @@ toy robot.
|
|
118
203
|
|
119
204
|
## Acknowledgements
|
120
205
|
- [RafaelChefe's Toy Robot Simulator](https://github.com/RafaelChefe/toy_robot)
|
121
|
-
- [
|
122
|
-
- [
|
206
|
+
- [Sandi Metz' Unit Testing Minimalist](https://youtu.be/URSWYvyc42M)
|
207
|
+
- [Daniel Steele](https://uk.linkedin.com/in/developerdansteele) and [Omnidev](https://omnidev.co.uk/)
|
208
|
+
|
data/lib/toy_robot.rb
CHANGED
@@ -1,11 +1,5 @@
|
|
1
|
-
require "pry"
|
2
1
|
require "toy_robot/client"
|
3
|
-
require "toy_robot/
|
4
|
-
require "toy_robot/arena"
|
5
|
-
require "toy_robot/command"
|
6
|
-
require "toy_robot/direction"
|
7
|
-
require "toy_robot/position"
|
8
|
-
require "toy_robot/null_position"
|
2
|
+
require "toy_robot/input"
|
9
3
|
|
10
4
|
module ToyRobot
|
11
5
|
def self.main
|
@@ -13,13 +7,9 @@ module ToyRobot
|
|
13
7
|
|
14
8
|
loop do
|
15
9
|
print "Input command: "
|
16
|
-
input =
|
17
|
-
break if input
|
18
|
-
client.
|
10
|
+
input = gets
|
11
|
+
break if input =~ /^\s*exit\s+/
|
12
|
+
client.command_for Input.new(input)
|
19
13
|
end
|
20
14
|
end
|
21
|
-
|
22
|
-
def self.get_input
|
23
|
-
gets.downcase.strip
|
24
|
-
end
|
25
15
|
end
|
data/lib/toy_robot/arena.rb
CHANGED
@@ -1,20 +1,10 @@
|
|
1
1
|
class Arena
|
2
|
-
def initialize(width
|
3
|
-
@
|
4
|
-
@
|
2
|
+
def initialize(width: 5, height: 5)
|
3
|
+
@columns = 0...width
|
4
|
+
@rows = 0...height
|
5
5
|
end
|
6
6
|
|
7
7
|
def inbounds?(x_coord, y_coord)
|
8
|
-
|
9
|
-
end
|
10
|
-
|
11
|
-
private
|
12
|
-
|
13
|
-
def max_x
|
14
|
-
@width - 1
|
15
|
-
end
|
16
|
-
|
17
|
-
def max_y
|
18
|
-
@height - 1
|
8
|
+
@columns.cover?(x_coord) && @rows.cover?(y_coord)
|
19
9
|
end
|
20
10
|
end
|
data/lib/toy_robot/client.rb
CHANGED
@@ -1,24 +1,13 @@
|
|
1
|
+
require "toy_robot/arena"
|
2
|
+
require "toy_robot/robot"
|
3
|
+
|
1
4
|
class Client
|
2
5
|
def initialize
|
3
6
|
@table = Arena.new width: 5, height: 5
|
4
7
|
@robot = Robot.new arena: @table
|
5
8
|
end
|
6
9
|
|
7
|
-
def
|
8
|
-
|
9
|
-
when /place\s+(\d+,\s*){2}([nesw]|(north)|(east)|(south)|(west))$/
|
10
|
-
PlaceCommand.new robot: @robot, command: input
|
11
|
-
when "move"
|
12
|
-
MoveCommand.new robot: @robot
|
13
|
-
when "left"
|
14
|
-
LeftCommand.new robot: @robot
|
15
|
-
when "right"
|
16
|
-
RightCommand.new robot: @robot
|
17
|
-
when "report"
|
18
|
-
ReportCommand.new robot: @robot
|
19
|
-
else
|
20
|
-
InvalidCommand.new
|
21
|
-
end
|
22
|
-
command.execute
|
10
|
+
def command_for(input)
|
11
|
+
input.new_command(@robot).execute
|
23
12
|
end
|
24
13
|
end
|
data/lib/toy_robot/command.rb
CHANGED
@@ -1,77 +1,21 @@
|
|
1
|
-
class
|
2
|
-
|
3
|
-
@robot = robot
|
4
|
-
@params = command[/\s.*/].delete(" ").split(",")
|
5
|
-
end
|
6
|
-
|
7
|
-
def execute
|
8
|
-
@robot.place Position.new(x_coord: x_coord,
|
9
|
-
y_coord: y_coord,
|
10
|
-
direction: direction)
|
11
|
-
end
|
12
|
-
|
13
|
-
private
|
14
|
-
|
15
|
-
def x_coord
|
16
|
-
@params[0].to_i
|
17
|
-
end
|
18
|
-
|
19
|
-
def y_coord
|
20
|
-
@params[1].to_i
|
21
|
-
end
|
22
|
-
|
23
|
-
def direction
|
24
|
-
case @params[2]
|
25
|
-
when "n", "north" then North
|
26
|
-
when "e", "east" then East
|
27
|
-
when "s", "south" then South
|
28
|
-
when "w", "west" then West
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
class MoveCommand
|
34
|
-
def initialize(robot:)
|
35
|
-
@robot = robot
|
36
|
-
end
|
37
|
-
|
38
|
-
def execute
|
39
|
-
@robot.move
|
40
|
-
end
|
41
|
-
end
|
1
|
+
class Command
|
2
|
+
attr_accessor :target, :params
|
42
3
|
|
43
|
-
|
44
|
-
|
45
|
-
@
|
46
|
-
end
|
4
|
+
def initialize(target: nil, params: nil)
|
5
|
+
@target = target
|
6
|
+
@params = params
|
47
7
|
|
48
|
-
|
49
|
-
@robot.left
|
8
|
+
post_initialize
|
50
9
|
end
|
51
|
-
end
|
52
10
|
|
53
|
-
|
54
|
-
def initialize(robot:)
|
55
|
-
@robot = robot
|
56
|
-
end
|
11
|
+
def post_initialize; end
|
57
12
|
|
58
13
|
def execute
|
59
|
-
|
14
|
+
return InvalidCommand.new.execute unless valid?
|
15
|
+
issue_command
|
60
16
|
end
|
61
|
-
end
|
62
17
|
|
63
|
-
|
64
|
-
|
65
|
-
@robot = robot
|
66
|
-
end
|
67
|
-
|
68
|
-
def execute
|
69
|
-
@robot.report
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
class InvalidCommand
|
74
|
-
def execute
|
75
|
-
puts "Invalid command"
|
18
|
+
def valid?
|
19
|
+
true
|
76
20
|
end
|
77
21
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require "toy_robot/move_command"
|
2
|
+
require "toy_robot/left_command"
|
3
|
+
require "toy_robot/right_command"
|
4
|
+
require "toy_robot/place_command"
|
5
|
+
require "toy_robot/report_command"
|
6
|
+
require "toy_robot/invalid_command"
|
7
|
+
|
8
|
+
class Input
|
9
|
+
def initialize(input)
|
10
|
+
@input = input.strip.downcase
|
11
|
+
end
|
12
|
+
|
13
|
+
def new_command(target)
|
14
|
+
to_class.new target: target, params: params
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def basename
|
20
|
+
@basename ||= @input.split(" ").first
|
21
|
+
end
|
22
|
+
|
23
|
+
def params
|
24
|
+
@params ||= @input.split(" ").drop 1
|
25
|
+
end
|
26
|
+
|
27
|
+
def classname
|
28
|
+
@classname ||= "#{basename.capitalize}Command"
|
29
|
+
end
|
30
|
+
|
31
|
+
def to_class
|
32
|
+
if Object.const_defined? classname
|
33
|
+
Object.const_get classname
|
34
|
+
else
|
35
|
+
InvalidCommand
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -1,11 +1,14 @@
|
|
1
1
|
class NullPosition
|
2
|
-
attr_reader :x_coord, :y_coord, :direction
|
2
|
+
attr_reader :x_coord, :y_coord, :direction
|
3
3
|
|
4
4
|
def initialize
|
5
5
|
@x_coord = nil
|
6
6
|
@y_coord = nil
|
7
7
|
@direction = nil
|
8
|
-
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_s
|
11
|
+
"No position"
|
9
12
|
end
|
10
13
|
|
11
14
|
def advance
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require "toy_robot/command"
|
2
|
+
|
3
|
+
class PlaceCommand < Command
|
4
|
+
def post_initialize
|
5
|
+
@params &&= @params.join.delete(" ").split ","
|
6
|
+
end
|
7
|
+
|
8
|
+
def issue_command
|
9
|
+
@target.place Position.new(x_coord: x_coord,
|
10
|
+
y_coord: y_coord,
|
11
|
+
direction: direction)
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def valid?
|
17
|
+
@params &&
|
18
|
+
@params.length == 3 &&
|
19
|
+
@params[0] =~ /^\d+$/ &&
|
20
|
+
@params[1] =~ /^\d+$/ &&
|
21
|
+
@params[2] =~ /^([nesw]|(north)|(east)|(south)|(west))$/
|
22
|
+
end
|
23
|
+
|
24
|
+
def x_coord
|
25
|
+
@params[0].to_i
|
26
|
+
end
|
27
|
+
|
28
|
+
def y_coord
|
29
|
+
@params[1].to_i
|
30
|
+
end
|
31
|
+
|
32
|
+
def direction
|
33
|
+
case @params[2]
|
34
|
+
when "n", "north" then North
|
35
|
+
when "e", "east" then East
|
36
|
+
when "s", "south" then South
|
37
|
+
when "w", "west" then West
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
data/lib/toy_robot/position.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require "toy_robot/direction"
|
2
|
+
|
1
3
|
class Position
|
2
4
|
attr_reader :x_coord, :y_coord, :direction
|
3
5
|
|
@@ -8,24 +10,25 @@ class Position
|
|
8
10
|
end
|
9
11
|
|
10
12
|
def advance
|
11
|
-
|
12
|
-
y_coord:
|
13
|
-
direction: @direction)
|
13
|
+
new_position(x_coord: @x_coord + @direction::X_DISPLACEMENT,
|
14
|
+
y_coord: @y_coord + @direction::Y_DISPLACEMENT)
|
14
15
|
end
|
15
16
|
|
16
17
|
def left
|
17
|
-
|
18
|
-
y_coord: @y_coord,
|
19
|
-
direction: @direction.left)
|
18
|
+
new_position direction: @direction.left
|
20
19
|
end
|
21
20
|
|
22
21
|
def right
|
23
|
-
|
24
|
-
y_coord: @y_coord,
|
25
|
-
direction: @direction.right)
|
22
|
+
new_position direction: @direction.right
|
26
23
|
end
|
27
24
|
|
28
25
|
def to_s
|
29
26
|
"#{@x_coord}, #{@y_coord}, #{@direction}"
|
30
27
|
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def new_position(x_coord: @x_coord, y_coord: @y_coord, direction: @direction)
|
32
|
+
Position.new x_coord: x_coord, y_coord: y_coord, direction: direction
|
33
|
+
end
|
31
34
|
end
|
data/lib/toy_robot/robot.rb
CHANGED
@@ -1,25 +1,29 @@
|
|
1
|
+
require "toy_robot/position"
|
2
|
+
require "toy_robot/null_position"
|
3
|
+
require "toy_robot/arena"
|
4
|
+
|
1
5
|
class Robot
|
2
|
-
|
6
|
+
attr_reader :position, :arena
|
3
7
|
|
4
|
-
def initialize(position: NullPosition.new, arena:)
|
8
|
+
def initialize(position: NullPosition.new, arena: Arena.new)
|
5
9
|
@position = position
|
6
10
|
@arena = arena
|
7
11
|
end
|
8
12
|
|
9
|
-
def place(
|
10
|
-
|
13
|
+
def place(position)
|
14
|
+
safely_go_to position
|
11
15
|
end
|
12
16
|
|
13
17
|
def move
|
14
|
-
|
18
|
+
safely_go_to @position.advance
|
15
19
|
end
|
16
20
|
|
17
21
|
def left
|
18
|
-
|
22
|
+
safely_go_to @position.left
|
19
23
|
end
|
20
24
|
|
21
25
|
def right
|
22
|
-
|
26
|
+
safely_go_to @position.right
|
23
27
|
end
|
24
28
|
|
25
29
|
def report
|
@@ -28,11 +32,9 @@ class Robot
|
|
28
32
|
|
29
33
|
private
|
30
34
|
|
31
|
-
def safely_go_to(
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
@position
|
36
|
-
end
|
35
|
+
def safely_go_to(position)
|
36
|
+
return unless position.x_coord && position.y_coord
|
37
|
+
return unless @arena.inbounds? position.x_coord, position.y_coord
|
38
|
+
@position = position
|
37
39
|
end
|
38
40
|
end
|
data/lib/toy_robot/version.rb
CHANGED
data/toy_robot.gemspec
CHANGED
@@ -6,7 +6,7 @@ require "toy_robot/version"
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
7
|
spec.name = "another_toy_robot"
|
8
8
|
spec.version = ToyRobot::VERSION
|
9
|
-
spec.date = "2016-12-
|
9
|
+
spec.date = "2016-12-05"
|
10
10
|
spec.authors = "Sheldon J. Johnson"
|
11
11
|
spec.email = "sheldon.j.johnson@outlook.com"
|
12
12
|
spec.homepage = "https://github.com/drzel/toy_robot"
|
@@ -24,4 +24,10 @@ Gem::Specification.new do |spec|
|
|
24
24
|
|
25
25
|
spec.bindir = "bin"
|
26
26
|
spec.executables << "toy_robot"
|
27
|
+
|
28
|
+
spec.add_development_dependency "rspec", "~> 3.5"
|
29
|
+
spec.add_development_dependency "rake", "~> 11.3"
|
30
|
+
spec.add_development_dependency "factory_girl", "~> 4.0"
|
31
|
+
spec.add_development_dependency "simplecov", "~> 0.12"
|
32
|
+
spec.add_development_dependency "codeclimate-test-reporter", "~> 1.0"
|
27
33
|
end
|
metadata
CHANGED
@@ -1,15 +1,85 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: another_toy_robot
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sheldon J. Johnson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-12-
|
12
|
-
dependencies:
|
11
|
+
date: 2016-12-05 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rspec
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '3.5'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '3.5'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '11.3'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '11.3'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: factory_girl
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '4.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '4.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: simplecov
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0.12'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0.12'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: codeclimate-test-reporter
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '1.0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '1.0'
|
13
83
|
description: The application is a simulation of a toy robot moving on a square tabletop. It
|
14
84
|
is an example of a well tested, object oriented design, employing the command design
|
15
85
|
pattern.
|
@@ -35,8 +105,15 @@ files:
|
|
35
105
|
- lib/toy_robot/client.rb
|
36
106
|
- lib/toy_robot/command.rb
|
37
107
|
- lib/toy_robot/direction.rb
|
108
|
+
- lib/toy_robot/input.rb
|
109
|
+
- lib/toy_robot/invalid_command.rb
|
110
|
+
- lib/toy_robot/left_command.rb
|
111
|
+
- lib/toy_robot/move_command.rb
|
38
112
|
- lib/toy_robot/null_position.rb
|
113
|
+
- lib/toy_robot/place_command.rb
|
39
114
|
- lib/toy_robot/position.rb
|
115
|
+
- lib/toy_robot/report_command.rb
|
116
|
+
- lib/toy_robot/right_command.rb
|
40
117
|
- lib/toy_robot/robot.rb
|
41
118
|
- lib/toy_robot/version.rb
|
42
119
|
- toy_robot.gemspec
|