toybot 1.0.0

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: 49c78135d65da889f15226744edb5f9112e35f21
4
+ data.tar.gz: 219588e93302a02dabfb75e147e7481f6d26a1dc
5
+ SHA512:
6
+ metadata.gz: 4871e41bcbf4d5399648144d05c5ae4fe90227aac8baef2f0554bd0a9284548c1ca39cf746d5457b87dfa53e0c5168255b10278c1c3124afab37f83c70a5ce8a
7
+ data.tar.gz: 38f92f0f1f4e05e7fd3a71d74c395ccd07efb815066cce60c376addcfbe7acc441e111843831e2bed0f363018c9e193e55e1cecb508002d3c49fcfe2d039aabf
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
@@ -0,0 +1 @@
1
+ 2.2.2
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.2
4
+ before_install: gem install bundler -v 1.10.5
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in toybot.gemspec
4
+ gemspec
@@ -0,0 +1,117 @@
1
+ # toy-robot
2
+
3
+ ### Description
4
+
5
+ toy-robot is a simulator of a toy robot that moves on a tabletop.
6
+
7
+ ### Requirements
8
+
9
+ - You need [RubyGems](https://rubygems.org/pages/download).
10
+ - You need [Bundler](http://bundler.io/)
11
+
12
+ To install Bundler from rubygems:
13
+
14
+ ```bash
15
+ $ gem install bundler
16
+ ```
17
+
18
+ ### Install
19
+
20
+ ```bash
21
+ $ bundle install
22
+ ```
23
+
24
+ This will install the few required dependencies specified in `toybot.gemspec`
25
+
26
+ **Run tests**
27
+
28
+ You can check that everything works correctly by running the tests:
29
+
30
+ ```bash
31
+ $ bundle exec rake
32
+ ```
33
+
34
+ ### Usage
35
+
36
+ **Start bot**
37
+
38
+ ```bash
39
+ $ bundle exec bin/toy-robot
40
+ ```
41
+
42
+ It is also possible to give a size to the tabletop like so:
43
+
44
+ ```bash
45
+ $ bundle exec bin/toy-robot WIDTH HEIGHT
46
+ ```
47
+
48
+ ### Error handling
49
+
50
+ - Toybot is quite permissive with the input as long as it respects the number of arguments, and uses the comma separator.
51
+ - Toybot is not very smart, but he is trying. Any invalid input will freak him out and he will display a little notice.
52
+
53
+ ### Implementation details
54
+
55
+ Toybot is made of several components:
56
+
57
+ 1. Tabletop
58
+
59
+ The `Tabletop` class is a simple abstraction of a tabletop with a `width` and a `height`.
60
+
61
+ - By default, the size of the tabletop is infinite.
62
+ - The tabletop only has positive coordinates starting at x(0) and y(0).
63
+ - The tabletop cannot be smaller than 1 by 1.
64
+
65
+ **where**: `lib/toybot/tabletop.rb`
66
+
67
+ 2. Direction
68
+
69
+ The `Direction` class abstract the notion of cardinal directions.
70
+
71
+ - It can be rotated clockwise or counter clockwise of 90deg.
72
+
73
+ **where**: `lib/toybot/direction.rb`
74
+
75
+ 3. Bot
76
+
77
+ Finally, our little robot.
78
+
79
+ - The bot needs to be initialized with a tabletop object.
80
+ - It can be initialized and run in one time with:
81
+
82
+ ```ruby
83
+ Toybot::Bot.start(tabletop)
84
+ ```
85
+
86
+ - It implements internally all the possible actions.
87
+ - Actions are called by passing a message to the bot object, deducted from the input.
88
+
89
+ **where**: `lib/toybot/bot.rb`
90
+
91
+ ### Specifications
92
+
93
+ toy-robot is a simulator of a toy robot that moves on a tabletop.
94
+
95
+ toy-robot reads instructions from STDIN, executing them one at a time until EOF is reached. (On a Linux or OSX system, type C-d to generate an EOF character).
96
+
97
+ valid commands
98
+
99
+ PLACE X,Y,FACING
100
+
101
+ Put the toy robot on the table in position X,Y and facing NORTH, SOUTH, EAST or WEST. If the robot is already placed, issuing another valid PLACE command will place the robot in the newly specified location.
102
+
103
+ MOVE
104
+
105
+ Moves the toy robot one unit forward in the direction it is currently facing.
106
+
107
+ LEFT
108
+
109
+ Rotates the robot 90 degrees to the left (i.e. counter-clockwise) without changing the position of the robot.
110
+
111
+ RIGHT
112
+
113
+ Rotates the robot 90 degrees to the right (i.e. clockwise) without changing the position of the robot.
114
+
115
+ REPORT
116
+
117
+ Announces the X,Y and F of the robot.
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList['test/**/*_test.rb']
8
+ end
9
+
10
+ task :default => :test
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "toybot"
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
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'toybot'
4
+
5
+ if ARGV.size == 2
6
+ tabletop = Toybot::Tabletop.new width: ARGV[0].to_i, height: ARGV[1].to_i
7
+ else
8
+ tabletop = Toybot::Tabletop.new
9
+ end
10
+
11
+ Toybot::Bot.start tabletop
@@ -0,0 +1,7 @@
1
+ require "toybot/version"
2
+ require 'toybot/tabletop'
3
+ require 'toybot/bot'
4
+ require 'toybot/direction'
5
+
6
+ module Toybot
7
+ end
@@ -0,0 +1,173 @@
1
+ class Toybot::Bot
2
+ # The format of the output of the `#report` method
3
+ REPORT_FORMAT = "[^_^] *bip bop* -( My position is X:%d Y:%d facing %s! )"
4
+ ERROR_REPORTS = [
5
+ "[x_x] *tuuuuut* -( What do you mean? )",
6
+ "[T_T] *tuuuuut* -( I can't help you, but Siri might... )",
7
+ "[o_0] *tuuuuut* -( Bonjour, parlez vous francais? )",
8
+ ]
9
+ USAGE = <<-EOS
10
+
11
+ Here's what you can do:
12
+ -----------------------
13
+
14
+ PLACE X, Y, F - Put the toy robot on the table in position X,Y
15
+ and facing NORTH, SOUTH, EAST or WEST. If the robot is already
16
+ placed, issuing another valid PLACE command will place the robot
17
+ in the newly specified location
18
+
19
+ example: PLACE 24, 42, SOUTH
20
+
21
+ MOVE
22
+ Moves the toy robot one unit forward in the direction it is currently
23
+ facing.
24
+
25
+ LEFT
26
+ Rotates the robot 90 degrees to the left (i.e. counter-clockwise) without
27
+ changing the position of the robot.
28
+
29
+ RIGHT
30
+ Rotates the robot 90 degrees to the right (i.e. clockwise) without changing
31
+ the position of the robot.
32
+
33
+ REPORT
34
+ Announces the X,Y and F of the robot.
35
+
36
+ EOS
37
+
38
+ # Whitelist of actions that the bot knows how to execute
39
+ ACTIONS = [:place, :move, :left, :right, :report]
40
+
41
+ # The bot entry point.
42
+ # It takes a `Toybot::Tabletop` as the first argument.
43
+ def self.start tabletop
44
+ self.new(tabletop).run
45
+ end
46
+
47
+ # Initialize a new `Bot` on a given `Tabletop`
48
+ # The bot has a default position of `{x: 0, y: 0, facing: :north}`
49
+ def initialize tabletop = Toybot::Tabletop.new
50
+ @tabletop = tabletop
51
+ @x, @y, @facing = 0, 0, Toybot::Direction.new(:north)
52
+ end
53
+
54
+ # Run loop of the bot
55
+ # Wait for input from STDIN, parse, execute, repeat until EOF
56
+ def run
57
+ while (input = $stdin.gets) do
58
+ action, args = self.parse_input(input)
59
+ self.execute action, args unless action == :no_action
60
+ end
61
+ end
62
+
63
+ # Returns the action and an array of arguments.
64
+ # It does not perform any validation on the input.
65
+ def parse_input input
66
+ input = input.chomp
67
+ arr = input.split
68
+ action = arr.shift || :no_action
69
+ return action.downcase.to_sym, arr.join.split(',')
70
+ end
71
+
72
+ # It takes the action and the arguments as first and second arguments.
73
+ # 1. Validate that the action is whitelisted
74
+ # 2. Fire the corresponding method, with the arguments if needed.
75
+ def execute action, args
76
+ if ACTIONS.include? action
77
+ if args.any?
78
+ self.send action, *args
79
+ else
80
+ self.send action
81
+ end
82
+ else
83
+ self.report_error
84
+ end
85
+ rescue ArgumentError
86
+ self.report_error
87
+ end
88
+
89
+ ############################################################
90
+ # Bot actions
91
+ #
92
+ # All bot actions return the bot position to facilitate
93
+ # testing.
94
+ ############################################################
95
+
96
+ def place x, y, facing
97
+ @x = x.to_i
98
+ @y = y.to_i
99
+ @facing.value = facing.downcase.to_sym
100
+ self.position
101
+ end
102
+
103
+ def right
104
+ @facing.rotate_clockwise!
105
+ self.position
106
+ end
107
+
108
+ def left
109
+ @facing.rotate_counter_clockwise!
110
+ self.position
111
+ end
112
+
113
+ def move
114
+ case @facing.value
115
+ when :north
116
+ self.move_up
117
+ when :east
118
+ self.move_right
119
+ when :south
120
+ self.move_down
121
+ when :west
122
+ self.move_left
123
+ end
124
+ self.position
125
+ end
126
+
127
+ def report
128
+ puts self.to_s
129
+ self.position
130
+ end
131
+
132
+ ############################################################
133
+ # Bot movement rules
134
+ ############################################################
135
+
136
+ def move_down
137
+ @y -= @y > 0 ? 1 : 0
138
+ end
139
+
140
+ def move_up
141
+ @y += @y < @tabletop.height ? 1 : 0
142
+ end
143
+
144
+ def move_left
145
+ @x -= @x > 0 ? 1 : 0
146
+ end
147
+
148
+ def move_right
149
+ @x += @x < @tabletop.width ? 1 : 0
150
+ end
151
+
152
+
153
+ ############################################################
154
+ # Bot reporting
155
+ ############################################################
156
+
157
+ def position
158
+ {x: @x, y: @y, facing: @facing.value}
159
+ end
160
+
161
+ def to_s
162
+ REPORT_FORMAT % [@x, @y, @facing.to_s]
163
+ end
164
+
165
+ def report_error
166
+ puts
167
+ puts "ERROR REPORT ======================================================================"
168
+ puts ERROR_REPORTS.sample
169
+ puts USAGE
170
+ puts "==================================================================================="
171
+ puts
172
+ end
173
+ end
@@ -0,0 +1,25 @@
1
+ class Toybot::Direction
2
+ attr_reader :value
3
+
4
+ DIRECTIONS = [:north, :east, :south, :west]
5
+
6
+ def initialize facing = :north
7
+ self.value = facing
8
+ end
9
+
10
+ def value= facing
11
+ @value = facing if DIRECTIONS.include? facing
12
+ end
13
+
14
+ def rotate_clockwise!
15
+ self.value = DIRECTIONS[DIRECTIONS.index(@value) + 1] || DIRECTIONS[0]
16
+ end
17
+
18
+ def rotate_counter_clockwise!
19
+ self.value = DIRECTIONS[DIRECTIONS.index(@value) - 1]
20
+ end
21
+
22
+ def to_s
23
+ @value.to_s
24
+ end
25
+ end
@@ -0,0 +1,19 @@
1
+ class Toybot::Tabletop
2
+ attr_accessor :width, :height
3
+
4
+ # Default values for tabletop x & y
5
+ # +1.0/0.0 => Infinity
6
+ DEFAULT_TABLETOP_WIDTH = +1.0/0.0
7
+ DEFAULT_TABLETOP_HEIGHT = +1.0/0.0
8
+
9
+ # A Tabletop has a width and height (Infinity by default).
10
+ # A Tabletop has a minimum size of 1 by 1.
11
+ def initialize width: DEFAULT_TABLETOP_WIDTH, height: DEFAULT_TABLETOP_HEIGHT
12
+ @width = width > 0 ? width : 1
13
+ @height = height > 0 ? height : 1
14
+ end
15
+
16
+ def size
17
+ {width: self.width, height: self.height}
18
+ end
19
+ end
@@ -0,0 +1,3 @@
1
+ module Toybot
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,30 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'toybot/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "toybot"
8
+ spec.version = Toybot::VERSION
9
+ spec.authors = ["Arnaud MESUREUR"]
10
+ spec.email = ["arnaud.mesureur@gmail.com"]
11
+
12
+ spec.summary = %q{BIP BOP}
13
+
14
+ # Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
15
+ # delete this section to allow pushing this gem to any host.
16
+ # if spec.respond_to?(:metadata)
17
+ # spec.metadata['allowed_push_host'] = "TODO: Set to 'http://mygemserver.com'"
18
+ # else
19
+ # raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
20
+ # end
21
+
22
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
23
+ spec.bindir = "exe"
24
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
25
+ spec.require_paths = ["lib"]
26
+
27
+ spec.add_development_dependency "bundler", "~> 1.10"
28
+ spec.add_development_dependency "rake", "~> 10.0"
29
+ spec.add_development_dependency "minitest"
30
+ end
metadata ADDED
@@ -0,0 +1,100 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: toybot
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Arnaud MESUREUR
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2015-09-16 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.10'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.10'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
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
+ description:
56
+ email:
57
+ - arnaud.mesureur@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - ".gitignore"
63
+ - ".ruby-version"
64
+ - ".travis.yml"
65
+ - Gemfile
66
+ - README.md
67
+ - Rakefile
68
+ - bin/console
69
+ - bin/setup
70
+ - bin/toy-robot
71
+ - lib/toybot.rb
72
+ - lib/toybot/bot.rb
73
+ - lib/toybot/direction.rb
74
+ - lib/toybot/tabletop.rb
75
+ - lib/toybot/version.rb
76
+ - toybot.gemspec
77
+ homepage:
78
+ licenses: []
79
+ metadata: {}
80
+ post_install_message:
81
+ rdoc_options: []
82
+ require_paths:
83
+ - lib
84
+ required_ruby_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ required_rubygems_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ requirements: []
95
+ rubyforge_project:
96
+ rubygems_version: 2.4.5
97
+ signing_key:
98
+ specification_version: 4
99
+ summary: BIP BOP
100
+ test_files: []