rubbot 0.1.0

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: d62ad256e0b37caeff3ba3c5d4006ad13c769279
4
+ data.tar.gz: c58dafd156d9978418bd54263030999054b1b305
5
+ SHA512:
6
+ metadata.gz: c51d1bd20da054489b1fd78317160f8da079bd6d53c7a73ce85bf53d1d4ced15860e7d861191bb6f92846641c17ed7612e4b46c4de7938f7b5fbd29c9b8a8d78
7
+ data.tar.gz: 6e8dc052b02f7d688b33e4c31ee1070437e6514907008b111164048a36049abf0166127d7f652dbc196368937dfe573a32b4d15c0927d423568ea74276789547
data/bin/rubbot ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubbot'
4
+
5
+ puts "Welcome to Rubbot!"
6
+ puts "------------------"
7
+
8
+ # Init and run 'Rubbot'
9
+ rubbot = Rubbot.new(Grid.new(5, 5)) and rubbot.start
10
+
data/lib/grid.rb ADDED
@@ -0,0 +1,2 @@
1
+ class Grid < Struct.new(:width, :height)
2
+ end
data/lib/position.rb ADDED
@@ -0,0 +1,49 @@
1
+ class Position < Struct.new(:x, :y, :orientation)
2
+ NORTH = :north
3
+ EAST = :east
4
+ SOUTH = :south
5
+ WEST = :west
6
+
7
+ def advance
8
+ case orientation
9
+ when NORTH
10
+ Position.new(x, y + 1, orientation)
11
+ when EAST
12
+ Position.new(x + 1, y, orientation)
13
+ when SOUTH
14
+ Position.new(x, y - 1, orientation)
15
+ when WEST
16
+ Position.new(x - 1, y, orientation)
17
+ else
18
+ self
19
+ end
20
+ end
21
+
22
+ def left
23
+ rotate -1
24
+ end
25
+
26
+ def right
27
+ rotate 1
28
+ end
29
+
30
+ def valid?(grid)
31
+ (0...grid.width).include?(x) && (0...grid.height).include?(y)
32
+ end
33
+
34
+ def to_s
35
+ "#{x},#{y},#{orientation.to_s.upcase}"
36
+ end
37
+
38
+ private
39
+
40
+ def rotate(by)
41
+ facing_index = orientations.index(orientation)
42
+ facing = orientations.rotate(facing_index).rotate(by).first
43
+ Position.new(x, y, facing)
44
+ end
45
+
46
+ def orientations
47
+ [NORTH, EAST, SOUTH, WEST]
48
+ end
49
+ end
data/lib/robot.rb ADDED
@@ -0,0 +1,44 @@
1
+ require_relative 'grid'
2
+ require_relative 'position'
3
+
4
+ class Robot
5
+ attr_reader :position
6
+
7
+ UNPLACED_NOTICE = "Robot should be placed first."
8
+
9
+ def initialize(grid)
10
+ @grid = grid
11
+ @position = Position.new(nil, nil, nil)
12
+ end
13
+
14
+ def place(position)
15
+ update_position position
16
+ end
17
+
18
+ def move
19
+ update_position @position.advance
20
+ end
21
+
22
+ def rotate_left
23
+ update_position @position.left
24
+ end
25
+
26
+ def rotate_right
27
+ update_position @position.right
28
+ end
29
+
30
+ def report
31
+ return UNPLACED_NOTICE unless placed?
32
+ @position.to_s
33
+ end
34
+
35
+ def placed?
36
+ @position.valid? @grid
37
+ end
38
+
39
+ private
40
+
41
+ def update_position(new_position)
42
+ @position = new_position if new_position.valid? @grid
43
+ end
44
+ end
data/lib/rubbot.rb ADDED
@@ -0,0 +1,29 @@
1
+ # Trap early interrupts
2
+ Signal.trap("INT") do
3
+ puts "Bye-bye!"
4
+ exit 1
5
+ end
6
+
7
+ require_relative 'rubbot_cli'
8
+ require_relative 'robot'
9
+
10
+ class Rubbot
11
+ def initialize(grid, options = {})
12
+ # Optionally accept redefined standard I/O
13
+ @stdin = options.fetch(:stdin) { STDIN }
14
+ @stdout = options.fetch(:stdout) { STDOUT }
15
+ @robot = Robot.new(grid)
16
+ end
17
+
18
+ def start
19
+ while input = @stdin.gets
20
+ begin
21
+ cmd = Commands::parse(input)
22
+ cmd.execute(@robot, output: @stdout)
23
+ rescue Commands::NoCommandError, RobotInterface::Place::InvalidFormatError => e
24
+ @stdout << "Invalid input: #{e.message}\n"
25
+ @stdout << RobotInterface::Help::print_help
26
+ end
27
+ end
28
+ end
29
+ end
data/lib/rubbot_cli.rb ADDED
@@ -0,0 +1,98 @@
1
+ module RobotInterface
2
+ class Command
3
+ NoArgumentsError = Class.new(Exception)
4
+
5
+ def initialize(args = [])
6
+ @args = args
7
+ end
8
+ end
9
+
10
+ class Place < Command
11
+ FORMAT = /-?\d+,-?\d+,(NORTH|EAST|SOUTH|WEST)\s*$/mi
12
+
13
+ InvalidFormatError = Class.new(Exception)
14
+
15
+ def initialize(args)
16
+ super
17
+ validate_format args
18
+ @x = args.shift.to_i
19
+ @y = args.shift.to_i
20
+ @orientation = Position.const_get(args.shift.upcase)
21
+ end
22
+
23
+ def execute(robot, options = {})
24
+ robot.place Position.new(@x, @y, @orientation)
25
+ end
26
+
27
+ private
28
+
29
+ def validate_format(argv)
30
+ if args = argv.join(',') and args.match(FORMAT).nil?
31
+ raise InvalidFormatError.new "'PLACE' format is invalid : '#{args}'"
32
+ end
33
+ end
34
+ end
35
+
36
+ class Move < Command
37
+ def execute(robot, options = {}) robot.move end
38
+ end
39
+
40
+ class Left < Command
41
+ def execute(robot, options = {}) robot.rotate_left end
42
+ end
43
+
44
+ class Right < Command
45
+ def execute(robot, options = {}) robot.rotate_right end
46
+ end
47
+
48
+ class Report < Command
49
+ def execute(robot, options = {})
50
+ output = options.fetch(:output)
51
+ output << robot.report + "\n"
52
+ end
53
+ end
54
+
55
+ class Help < Command
56
+ def execute(robot, options = {})
57
+ options.fetch(:output) << self.class::print_help
58
+ end
59
+
60
+ def self.print_help
61
+ help_message = <<-END.gsub(/^ {8}/, '')
62
+ Robot Commands:
63
+ ------------------------------------------------------
64
+ PLACE Places the robot at X, Y facing an orientation
65
+ Orientations accepted: NORTH, EAST, SOUTH, WEST
66
+ Format: 'X,Y,ORIENTATION'. i.e.: '2,3,NORTH'
67
+ MOVE Moves the robot in current direction
68
+ LEFT Turns the robot left
69
+ RIGHT Turns the robot right
70
+ REPORT Prints current state of the robot
71
+ HELP Prints this help message
72
+ ------------------------------------------------------
73
+ END
74
+ end
75
+ end
76
+ end
77
+
78
+ module Commands
79
+ # Map input instructions to Robot actions
80
+ COMMANDS_MAP = {
81
+ "PLACE" => RobotInterface::Place,
82
+ "MOVE" => RobotInterface::Move,
83
+ "LEFT" => RobotInterface::Left,
84
+ "RIGHT" => RobotInterface::Right,
85
+ "REPORT" => RobotInterface::Report,
86
+ "HELP" => RobotInterface::Help
87
+ }
88
+
89
+ NoCommandError = Class.new(Exception)
90
+
91
+ def self.parse(input)
92
+ cmd, args = input.split
93
+ args = String(args).split(",")
94
+ cmd_class = COMMANDS_MAP[String(cmd).upcase]
95
+ raise NoCommandError.new "'#{cmd}'' is undefined." unless cmd_class
96
+ cmd_class.new args
97
+ end
98
+ end
data/lib/utils.rb ADDED
@@ -0,0 +1,21 @@
1
+ module Utils
2
+ # Standard input simulator
3
+ class StdinSimulator
4
+ attr_reader :input_queue
5
+
6
+ def initialize
7
+ # Represent an input queue as an array
8
+ @input_queue = []
9
+ end
10
+
11
+ def <<(input)
12
+ # Add an element to the input queue
13
+ @input_queue << input
14
+ end
15
+
16
+ def gets
17
+ # Dequeue the first element in the queue
18
+ @input_queue.shift
19
+ end
20
+ end
21
+ end
metadata ADDED
@@ -0,0 +1,107 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rubbot
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Daniel Stankevich
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-09-15 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
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: rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: turnip
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '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'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: Toy Robot simulation implementation in Ruby.
70
+ email: standeo@gmail.com
71
+ executables:
72
+ - rubbot
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - bin/rubbot
77
+ - lib/grid.rb
78
+ - lib/position.rb
79
+ - lib/robot.rb
80
+ - lib/rubbot.rb
81
+ - lib/rubbot_cli.rb
82
+ - lib/utils.rb
83
+ homepage: http://rubygems.org/gems/rubbot
84
+ licenses:
85
+ - MIT
86
+ metadata: {}
87
+ post_install_message:
88
+ rdoc_options: []
89
+ require_paths:
90
+ - lib
91
+ required_ruby_version: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - '>='
94
+ - !ruby/object:Gem::Version
95
+ version: 2.0.0
96
+ required_rubygems_version: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - '>='
99
+ - !ruby/object:Gem::Version
100
+ version: '0'
101
+ requirements: []
102
+ rubyforge_project:
103
+ rubygems_version: 2.2.2
104
+ signing_key:
105
+ specification_version: 4
106
+ summary: Toy Robot simulation.
107
+ test_files: []