toy_robot 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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 470b7ee06374f2b4e17346a8a842fb990766dd19
4
+ data.tar.gz: 5e6c4ba76194f3c01f500c54738518818b2317fb
5
+ SHA512:
6
+ metadata.gz: c23a350702a5d232edfc69c501c5c7bcc3f5e12fa61b7f570089886761d1e5df1983b0b2e78321056f17ff0f88e7825bab67239a36c8a6f932e9a31cd81d1f98
7
+ data.tar.gz: 0ee1187e09d65ae884102910bafa0d73bdb9bc68778f509ced990b03454a19b6ead3433dcca85a941ee0e96d4fa908fde82449dd12767984f26638ed82a91cd7
@@ -0,0 +1,34 @@
1
+ *.gem
2
+ *.rbc
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/reports/
8
+ /test/tmp/
9
+ /test/version_tmp/
10
+ /tmp/
11
+
12
+ ## Specific to RubyMotion:
13
+ .dat*
14
+ .repl_history
15
+ build/
16
+
17
+ ## Documentation cache and generated files:
18
+ /.yardoc/
19
+ /_yardoc/
20
+ /doc/
21
+ /rdoc/
22
+
23
+ ## Environment normalisation:
24
+ /.bundle/
25
+ /lib/bundler/man/
26
+
27
+ # for a library or gem, you might want to ignore these files since the code is
28
+ # intended to run in multiple environments; otherwise, check them in:
29
+ Gemfile.lock
30
+ # .ruby-version
31
+ # .ruby-gemset
32
+
33
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
34
+ .rvmrc
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 louman
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 all
13
+ 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 THE
21
+ SOFTWARE.
22
+
@@ -0,0 +1,18 @@
1
+ # Toy_Robot
2
+
3
+ Welcome to the toy robot simulator.
4
+
5
+ ## Usage
6
+
7
+ ```ruby
8
+ gem install toy_robot
9
+
10
+ toy_robot
11
+ ```
12
+ and follow instructions :)
13
+
14
+ ## Specs
15
+
16
+ ```ruby
17
+ rspec
18
+ ```
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ require_relative '../lib/toy_robot'
3
+
4
+ ToyRobot::Bin::Runner.new.start
@@ -0,0 +1,19 @@
1
+ require 'asciiart'
2
+ require 'forwardable'
3
+ require 'rainbow'
4
+ require 'terminal-table'
5
+
6
+ require 'toy_robot/roboto'
7
+ require 'toy_robot/roboto/brain'
8
+ require 'toy_robot/roboto/motor_cortex'
9
+ require 'toy_robot/roboto/speech'
10
+ require 'toy_robot/table'
11
+ require 'toy_robot/manifest_reader'
12
+ require 'toy_robot/simulator'
13
+
14
+ require 'toy_robot/bin/io_utils'
15
+ require 'toy_robot/bin/runner'
16
+
17
+ module ToyRobot
18
+
19
+ end
@@ -0,0 +1,38 @@
1
+ module ToyRobot
2
+ module Bin
3
+ module IOUtils
4
+
5
+ # puts a message and sleep
6
+ def print_with_delay(msg, delay_time=2)
7
+ _print msg
8
+ delay delay_time
9
+ end
10
+
11
+ # just a wrapper for puts
12
+ def _print(msg)
13
+ puts msg
14
+ end
15
+
16
+ # just a wrapper for sleep
17
+ def delay(delay_time)
18
+ sleep delay_time
19
+ end
20
+
21
+ # returns a yellowish string
22
+ def yellow(text)
23
+ Rainbow(text).yellow
24
+ end
25
+
26
+ # returns a greenish string
27
+ def green(text)
28
+ Rainbow(text).green
29
+ end
30
+
31
+ # returns a reddish string
32
+ def red(text)
33
+ Rainbow(text).red
34
+ end
35
+
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,108 @@
1
+ module ToyRobot
2
+ module Bin
3
+ class Runner
4
+
5
+ include IOUtils
6
+
7
+ attr_reader :simulator, :roboto, :selected_option
8
+
9
+ def initialize
10
+ @simulator = ToyRobot::Simulator.new
11
+ @roboto = @simulator.roboto
12
+ @roboto.name = robots.sample
13
+ end
14
+
15
+ def start
16
+ show_art
17
+ show_help
18
+ show_options
19
+ @selected_option = capture_input
20
+ handle_selected_option
21
+ end
22
+
23
+ private
24
+
25
+ def capture_input
26
+ gets.chomp.strip
27
+ end
28
+
29
+ def handle_selected_option
30
+ case selected_option
31
+ when '1'
32
+ input_by_hand
33
+ when '2'
34
+ input_from_file
35
+ else
36
+ _print 'Invalid option, terminating simulator.'
37
+ end
38
+ end
39
+
40
+ def input_by_hand
41
+ boot_roboto('Ok, preparing roboto for manual orders')
42
+ _print green("-- #{@roboto.name} reporting for duty. What is you first order sir?")
43
+ command = capture_input
44
+ while command
45
+ begin
46
+ @simulator.run([command])
47
+ rescue StandardError
48
+ _print red('Order not recognized, sir!')
49
+ end
50
+ _print green("#{@roboto.name} waiting for new orders, sir!")
51
+ command = capture_input
52
+ end
53
+ end
54
+
55
+ def input_from_file
56
+ boot_roboto('Ok, preparing roboto for orders manifest')
57
+ @simulator.run(read_manifest)
58
+ end
59
+
60
+ def read_manifest
61
+ ToyRobot::ManifestReader.new.read
62
+ end
63
+
64
+ def show_art
65
+ _print art
66
+ end
67
+
68
+ def show_help
69
+ _print help
70
+ end
71
+
72
+ def show_options
73
+ _print '1) Input orders by hand'
74
+ _print '2) Input orders from file'
75
+ end
76
+
77
+ def boot_roboto(acknowledge_message)
78
+ print_with_delay yellow(acknowledge_message)
79
+ print_with_delay yellow("Booting #{@roboto.name}")
80
+ print_with_delay yellow('Calibrating controls')
81
+ print_with_delay yellow('Activating AI')
82
+ print_with_delay yellow('1, 2, 3 testing')
83
+ end
84
+
85
+ def help
86
+ rows = []
87
+ rows << ['Type "exit" anytime to exit simulator']
88
+ rows << ['Valid commands are: PLACE, MOVE, LEFT, RIGHT, REPORT']
89
+ rows << ['PLACE: puts the toy robot on the table in position X,Y and facing NORTH, SOUTH, EAST or WEST.']
90
+ rows << ['MOVE: moves the toy robot one unit forward in the direction it is currently facing.']
91
+ rows << ['LEFT: rotates the robot 90 degrees counter-clockwise without changing the position of the robot.']
92
+ rows << ['RIGHT: rotates the robot 90 degrees clockwise without changing the position of the robot.']
93
+ rows << ['REPORT: announces the X,Y and F of the robot.']
94
+ table = Terminal::Table.new :rows => rows, title: 'Welcome to the Toy Robot Simulator!'
95
+ end
96
+
97
+ def robots
98
+ ['T-800', 'Optimus Prime', 'R2-D2', 'C-3PO', 'Data', 'Sonny', 'Wall-E', 'Rosey', 'Robocop', 'T-1000']
99
+ end
100
+
101
+ def art
102
+ art = AsciiArt.new(File.join(File.dirname(__FILE__), '..', 'files', 'roboto.jpg'))
103
+ art.to_ascii_art(width: 70)
104
+ end
105
+
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,9 @@
1
+ MOVE
2
+ PLACE 1,2,NORTH
3
+ LEFT
4
+ REPORT
5
+ LEFT
6
+ LEFT
7
+ REPORT
8
+ MOVE
9
+ REPORT
@@ -0,0 +1,16 @@
1
+ module ToyRobot
2
+ class ManifestReader
3
+
4
+ attr_reader :file
5
+
6
+ def initialize(file_path:nil)
7
+ @file_path = file_path || File.join(File.dirname(__FILE__), 'files', 'manifest.txt')
8
+ @file = File.open(@file_path)
9
+ end
10
+
11
+ def read
12
+ @file.each_line.map(&:strip)
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,90 @@
1
+ module ToyRobot
2
+ class Roboto
3
+
4
+ extend Forwardable
5
+
6
+ def_delegator :@brain, :speak
7
+ def_delegator :@brain, :motor_cortex, :location
8
+ def_delegator :@brain, :understand_order
9
+
10
+ attr_accessor :table_edges, :brain, :name
11
+
12
+ def initialize
13
+ @brain = Brain.new
14
+ @name = 'Roboto'
15
+ end
16
+
17
+ # Sends order's method
18
+ def execute_order(order)
19
+ if order[:args].nil?
20
+ send(order[:command])
21
+ else
22
+ send(order[:command], order[:args])
23
+ end
24
+ end
25
+
26
+ # Changes roboto location if is safe
27
+ # otherwise says advise message
28
+ def place(x:, y:, f:)
29
+ safe(x, y) do
30
+ location.reset(x: x.to_i, y: y.to_i, f: f.downcase.to_sym)
31
+ end
32
+ end
33
+
34
+ # Moves roboto one unit forward to facing direction if roboto is placed
35
+ # and it's safe
36
+ # otherwise says advise message
37
+ def move
38
+ if_placed do
39
+ x, y = location.forward_prediction
40
+ safe(x, y) do
41
+ location.forward
42
+ end
43
+ end
44
+ end
45
+
46
+ # Says current location if roboto is placed
47
+ # otherwise says advise message
48
+ def report
49
+ if_placed do
50
+ puts speak(location.to_s)
51
+ end
52
+ end
53
+
54
+ # Rotates roboto 90 degrees to the left if roboto is placed
55
+ # otherwise says advise message
56
+ def left
57
+ if_placed do
58
+ location.rotate_ccw
59
+ end
60
+ end
61
+
62
+ # Rotates roboto 90 degrees to the right if roboto is placed
63
+ # otherwise says advise message
64
+ def right
65
+ if_placed do
66
+ location.rotate_cw
67
+ end
68
+ end
69
+
70
+ # Returns true if location is nil
71
+ def placed?
72
+ !location.nil?
73
+ end
74
+
75
+ private
76
+
77
+ def safe(x, y)
78
+ to_safe_location?(x, y) ? yield : speak("No can do, sir! If #{name} move #{name} fall.")
79
+ end
80
+
81
+ def to_safe_location?(new_x, new_y)
82
+ new_x.between?(table_edges[:x][:min], table_edges[:x][:max]) && new_y.between?(table_edges[:y][:min], table_edges[:y][:max])
83
+ end
84
+
85
+ def if_placed
86
+ placed? ? yield : speak("#{name} not placed yet, sir!")
87
+ end
88
+
89
+ end
90
+ end
@@ -0,0 +1,38 @@
1
+ module ToyRobot
2
+ class Roboto
3
+ class Brain
4
+
5
+ extend Forwardable
6
+
7
+ def_delegator :@speech, :speak
8
+
9
+ attr_accessor :motor_cortex, :speech
10
+
11
+ def initialize
12
+ @motor_cortex = MotorCortex.new
13
+ @speech = Speech.new
14
+ end
15
+
16
+ def understand_order(order)
17
+ order = sanitized_order(order).split(' ')
18
+ method = order.shift.downcase.to_sym
19
+ if order.any?
20
+ arguments = sanitized_args(order.shift)
21
+ end
22
+ { command: method, args: arguments }
23
+ end
24
+
25
+ private
26
+
27
+ def sanitized_order(order)
28
+ order.strip.squeeze(' ')
29
+ end
30
+
31
+ def sanitized_args(args)
32
+ args = args.gsub(/ /, '').split(',')
33
+ { x: args[0].to_i, y: args[1].to_i, f: args[2].downcase.to_sym }
34
+ end
35
+
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,67 @@
1
+ module ToyRobot
2
+ class Roboto
3
+ class MotorCortex
4
+
5
+ attr_accessor :x, :y, :f
6
+
7
+ CARDINAL_DIRECTIONS = [:north, :east, :south, :west]
8
+ MOVE = { north: { x: 0, y: 1 },
9
+ east: { x: 1, y: 0 },
10
+ south: { x: 0, y: -1 },
11
+ west: { x: -1, y: 0 } }
12
+
13
+ def initialize(x: nil, y: nil, f: nil)
14
+ reset(x: x, y: y, f: f)
15
+ end
16
+
17
+ # Sets X, Y and forwarding direction
18
+ def reset(x:, y:, f:)
19
+ raise "#{f} is not a recognized direction" unless f.nil? || CARDINAL_DIRECTIONS.include?(f)
20
+ @x = x
21
+ @y = y
22
+ @f = f
23
+ end
24
+
25
+ # Rotates -90 degrees
26
+ def rotate_ccw
27
+ @f = rotation(-1)
28
+ end
29
+
30
+ # Rotates 90 degrees
31
+ def rotate_cw
32
+ @f = rotation(1) || CARDINAL_DIRECTIONS[0]
33
+ end
34
+
35
+ # Increaseas one unit to forwarding direction
36
+ def forward
37
+ new_x, new_y = forward_prediction
38
+ reset(x: new_x, y: new_y, f: @f)
39
+ end
40
+
41
+ # Calculates new position to move forward
42
+ def forward_prediction
43
+ return @x + MOVE[@f][:x], @y + MOVE[@f][:y]
44
+ end
45
+
46
+ # Returns a formated string with axis and forwarding direction
47
+ def to_s
48
+ "X: #{value_or_not_available(@x)}, Y: #{value_or_not_available(@y)}, F: #{value_or_not_available(@f)}"
49
+ end
50
+
51
+ # Returns true X or Y or F is nil
52
+ def nil?
53
+ @x.nil? || @y.nil? || @f.nil?
54
+ end
55
+
56
+ private
57
+
58
+ def value_or_not_available(value)
59
+ value.nil? ? 'N/A' : value
60
+ end
61
+
62
+ def rotation(step)
63
+ CARDINAL_DIRECTIONS[CARDINAL_DIRECTIONS.index(@f) + step]
64
+ end
65
+ end
66
+ end
67
+ end