toy 0.1.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: 4f0ff45fd29860f8d248a37b475b2a56176b5b22
4
+ data.tar.gz: f5b66908dc97de61cf30e4fa1812916e66eb6105
5
+ SHA512:
6
+ metadata.gz: ba9d7063eba65eca749ca6f6e2a077dd9e79eb91ae9bd3f00f8d5b2e6dba0ce807dacc64389b5df5947934bab40583cdc0a961a60f84bc59261cdb261557fc7d
7
+ data.tar.gz: 38c0cfe33473630901493bbb600fd58326f0ba0e091c4b0f80a4b2bf91f4b4b703d0bead1f7823e3e00c8dbc1270380e54162ecf04443709f968951a0891b1b9
@@ -0,0 +1,4 @@
1
+ lib/**/*.rb
2
+ README.md
3
+ ChangeLog.md
4
+ LICENSE.txt
@@ -0,0 +1,19 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ coverage
6
+ InstalledFiles
7
+ lib/bundler/man
8
+ pkg
9
+ rdoc
10
+ spec/reports
11
+ test/tmp
12
+ test/version_tmp
13
+ tmp
14
+
15
+ # YARD artifacts
16
+ .yardoc
17
+ _yardoc
18
+ doc/
19
+ vendor/
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --colour
@@ -0,0 +1,8 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 2.0.0
5
+ - 2.1.4
6
+ addons:
7
+ code_climate:
8
+ repo_token: 315a51b0a3c5c30885d590e04f4c92df0800f74973d33e762cb6da7b2c4ef51e
@@ -0,0 +1,3 @@
1
+ ### 0.1.0 / 2015-01-25 ###
2
+
3
+ * Initial release
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gem 'rake'
4
+ gemspec
@@ -0,0 +1,46 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ toy (0.1.0)
5
+
6
+ GEM
7
+ remote: http://rubygems.org/
8
+ specs:
9
+ codeclimate-test-reporter (0.4.6)
10
+ simplecov (>= 0.7.1, < 1.0.0)
11
+ diff-lcs (1.2.5)
12
+ docile (1.1.5)
13
+ json (1.8.2)
14
+ multi_json (1.10.1)
15
+ rake (10.4.2)
16
+ rdoc (4.2.0)
17
+ json (~> 1.4)
18
+ rspec (3.1.0)
19
+ rspec-core (~> 3.1.0)
20
+ rspec-expectations (~> 3.1.0)
21
+ rspec-mocks (~> 3.1.0)
22
+ rspec-core (3.1.7)
23
+ rspec-support (~> 3.1.0)
24
+ rspec-expectations (3.1.2)
25
+ diff-lcs (>= 1.2.0, < 2.0)
26
+ rspec-support (~> 3.1.0)
27
+ rspec-mocks (3.1.3)
28
+ rspec-support (~> 3.1.0)
29
+ rspec-support (3.1.2)
30
+ rubygems-tasks (0.2.4)
31
+ simplecov (0.9.1)
32
+ docile (~> 1.1.0)
33
+ multi_json (~> 1.0)
34
+ simplecov-html (~> 0.8.0)
35
+ simplecov-html (0.8.0)
36
+
37
+ PLATFORMS
38
+ ruby
39
+
40
+ DEPENDENCIES
41
+ codeclimate-test-reporter
42
+ rake
43
+ rdoc (~> 4.1)
44
+ rspec (~> 3.1)
45
+ rubygems-tasks (~> 0.2)
46
+ toy!
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2015 Ninoslav Milenovic
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,49 @@
1
+ # toy #
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/toy.svg)](http://badge.fury.io/rb/toy)
4
+ [![Build Status](https://travis-ci.org/rubyengineer/toy.svg?branch=master)](https://travis-ci.org/rubyengineer/toy)
5
+ [![Code Climate](https://codeclimate.com/github/rubyengineer/toy/badges/gpa.svg)](https://codeclimate.com/github/rubyengineer/toy)
6
+ [![Test Coverage](https://codeclimate.com/github/rubyengineer/toy/badges/coverage.svg)](https://codeclimate.com/github/rubyengineer/toy)
7
+ [![Dependency Status](https://gemnasium.com/rubyengineer/toy.svg)](https://gemnasium.com/rubyengineer/toy)
8
+
9
+ Simulation of a toy robot moving on a square tabletop. The robot is free to roam around the surface of the table, but must be prevented from falling to destruction. Any movement that would result in the robot falling from the table must be prevented, however further valid movement commands must still be allowed. Multiple robots should be able to roam around the surface of the same table.
10
+
11
+ ## Install ##
12
+ ```bash
13
+ $ gem install toy
14
+ ```
15
+
16
+ ## Usage ##
17
+ ```bash
18
+ $ toy
19
+ ```
20
+
21
+ ## Examples ##
22
+
23
+ Example Input and Output:
24
+
25
+ a)
26
+ `PLACE 0,0,NORTH`
27
+ `MOVE`
28
+ `REPORT`
29
+ Output: `0,1,NORTH`
30
+
31
+ b)
32
+ `PLACE 0,0,NORTH`
33
+ `LEFT`
34
+ `REPORT`
35
+ Output: `0,0,WEST`
36
+
37
+ c)
38
+ `PLACE 1,2,EAST`
39
+ `MOVE`
40
+ `MOVE`
41
+ `LEFT`
42
+ `MOVE`
43
+ `REPORT`
44
+ Output: `3,3,NORTH`
45
+
46
+ ### Copyright ###
47
+ Copyright (c) 2015 Ninoslav Milenovic
48
+
49
+ See LICENSE.txt for details.
@@ -0,0 +1,41 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'rake'
5
+
6
+ begin
7
+ gem 'rubygems-tasks', '~> 0.2'
8
+ require 'rubygems/tasks'
9
+
10
+ Gem::Tasks.new
11
+ rescue LoadError => e
12
+ warn e.message
13
+ warn 'Run `gem install rubygems-tasks` to install Gem::Tasks.'
14
+ end
15
+
16
+ begin
17
+ gem 'rdoc', '~> 4.1'
18
+ require 'rdoc/task'
19
+
20
+ RDoc::Task.new do |rdoc|
21
+ rdoc.title = 'trange_frange'
22
+ end
23
+ rescue LoadError => e
24
+ warn e.message
25
+ warn "Run `gem install rdoc` to install 'rdoc/task'."
26
+ end
27
+ task :doc => :rdoc
28
+
29
+ begin
30
+ gem 'rspec', '~> 3.1'
31
+ require 'rspec/core/rake_task'
32
+
33
+ RSpec::Core::RakeTask.new
34
+ rescue LoadError => e
35
+ task :spec do
36
+ abort 'Please run `gem install rspec` to install RSpec.'
37
+ end
38
+ end
39
+
40
+ task :test => :spec
41
+ task :default => :spec
data/bin/toy ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
4
+
5
+ require 'toy'
6
+
7
+ Toy::Controller.new.start
@@ -0,0 +1,9 @@
1
+ # encoding: utf-8
2
+
3
+ require_relative 'toy/unit'
4
+ require_relative 'toy/unit_collection'
5
+ require_relative 'toy/table'
6
+ require_relative 'toy/direction'
7
+ require_relative 'toy/robot'
8
+ require_relative 'toy/version'
9
+ require_relative 'toy/controller'
@@ -0,0 +1,99 @@
1
+ # encoding: utf-8
2
+
3
+ module Toy
4
+ class Controller
5
+ COMMANDS = %w[STOP HELP PLACE MOVE LEFT RIGHT REPORT]
6
+
7
+ attr_reader :robot
8
+
9
+ def initialize
10
+ @robot = Robot.new
11
+ end
12
+
13
+ def start
14
+ while command = gets
15
+ unless COMMANDS.include?(command.gsub(/^[A-Z]+/).first)
16
+ puts 'Invalid command! Type HELP for list of available commands.' and next
17
+ end
18
+
19
+ case command
20
+ when /STOP/
21
+ break
22
+ else
23
+ output = execute(command.strip)
24
+ puts output if output
25
+ end
26
+ end
27
+ end
28
+
29
+ private
30
+
31
+ def execute(command)
32
+ case command
33
+ when /HELP/
34
+ help
35
+ when /PLACE/
36
+ place(command)
37
+ when /MOVE/
38
+ move
39
+ when /LEFT/
40
+ left
41
+ when /RIGHT/
42
+ right
43
+ when /REPORT/
44
+ report
45
+ end
46
+ end
47
+
48
+ def help
49
+ "Available commands: #{COMMANDS.join(' ')}"
50
+ end
51
+
52
+ def place(command)
53
+ begin
54
+ x, y, facing = command.split(' ', 2).last.split(',')
55
+
56
+ x = x.to_i if x.strip.match(/^(\d)+$/)
57
+ y = y.to_i if y.strip.match(/^(\d)+$/)
58
+ facing = facing.strip.downcase.to_sym
59
+ rescue
60
+ return 'Invalid placement arguments!'
61
+ end
62
+
63
+ begin
64
+ @robot.place(x, y, facing) and return nil
65
+ rescue Toy::Direction::Error::DirectionError => e
66
+ e.message
67
+ rescue Toy::Unit::Error::CoordinateError => e
68
+ e.message
69
+ rescue Toy::Table::Error::TableError
70
+ "Not available!"
71
+ end
72
+ end
73
+
74
+ def move
75
+ action { @robot.move! }
76
+ end
77
+
78
+ def left
79
+ action { @robot.turn_left! }
80
+ end
81
+
82
+ def right
83
+ action { @robot.turn_right! }
84
+ end
85
+
86
+ def report
87
+ action do
88
+ x, y, facing = @robot.position
89
+ return "#{x},#{y},#{facing.upcase}"
90
+ end
91
+ end
92
+
93
+ def action(&execute)
94
+ yield execute and return nil
95
+ rescue Toy::Robot::Error::PlacementError => e
96
+ e.message
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,38 @@
1
+ # encoding: utf-8
2
+
3
+ module Toy
4
+ class Direction
5
+ NORTH = :north
6
+ EAST = :east
7
+ SOUTH = :south
8
+ WEST = :west
9
+
10
+ DIRECTION = [NORTH, EAST, SOUTH, WEST]
11
+
12
+ class << self
13
+ def rotate_left(direction)
14
+ element(direction, -1)
15
+ end
16
+
17
+ def rotate_right(direction)
18
+ element(direction, 1)
19
+ end
20
+
21
+ private
22
+
23
+ def element(direction, index)
24
+ raise Error::DirectionError unless DIRECTION.include?(direction)
25
+
26
+ DIRECTION[(DIRECTION.index(direction) + index) % DIRECTION.size]
27
+ end
28
+ end
29
+
30
+ module Error
31
+ class DirectionError < ArgumentError
32
+ def message
33
+ 'Invalid direction!'
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,66 @@
1
+ # encoding: utf-8
2
+
3
+ module Toy
4
+ class Robot
5
+ attr_reader :table, :facing
6
+
7
+ def initialize(table=Table.new, direction=Direction)
8
+ @table = table
9
+ @direction = direction
10
+ @facing = nil
11
+ end
12
+
13
+ def place(x, y, facing)
14
+ raise @direction::Error::DirectionError unless @direction::DIRECTION.include?(facing)
15
+
16
+ @table.hold!(x, y, self)
17
+ @facing = facing
18
+ end
19
+
20
+ def placed?
21
+ !!current_unit
22
+ end
23
+
24
+ def position
25
+ raise Error::PlacementError unless placed?
26
+
27
+ [current_unit.x, current_unit.y, @facing]
28
+ end
29
+
30
+ def move!
31
+ raise Error::PlacementError unless placed?
32
+
33
+ place(target.x, target.y, @facing) if target && target.available?
34
+ end
35
+
36
+ def turn_left!
37
+ raise Error::PlacementError unless placed?
38
+
39
+ @facing = @direction.rotate_left(@facing)
40
+ end
41
+
42
+ def turn_right!
43
+ raise Error::PlacementError unless placed?
44
+
45
+ @facing = @direction.rotate_right(@facing)
46
+ end
47
+
48
+ private
49
+
50
+ def current_unit
51
+ @table.unit_collection.find_by_object(self)
52
+ end
53
+
54
+ def target
55
+ @table.unit_collection.find_by_direction_of(current_unit.x, current_unit.y, @facing)
56
+ end
57
+
58
+ module Error
59
+ class PlacementError < StandardError
60
+ def message
61
+ 'Robot is not placed!'
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,52 @@
1
+ # encoding: utf-8
2
+
3
+ module Toy
4
+ class Table
5
+ X_SIZE = 5
6
+ Y_SIZE = 5
7
+
8
+ # X_STARTS_FROM = WEST
9
+ # Y_STARTS_FROM = SOUTH
10
+
11
+ attr_reader :unit_collection
12
+
13
+ def initialize(unit=Unit)
14
+ @unit = unit
15
+ @unit_collection = generate_collection!
16
+ end
17
+
18
+ def hold!(x, y, object)
19
+ raise @unit::Error::CoordinateError unless x.is_a?(Fixnum)
20
+ raise @unit::Error::CoordinateError unless y.is_a?(Fixnum)
21
+
22
+ target_unit = @unit_collection.find_by_coordinates(x, y)
23
+
24
+ if target_unit && target_unit.available?
25
+ @unit_collection.find_by_object(object) && @unit_collection.find_by_object(object).release!
26
+ target_unit.hold!(object)
27
+ else
28
+ raise Error::TableError
29
+ end
30
+ end
31
+
32
+ private
33
+
34
+ def generate_collection!
35
+ UnitCollection.new.tap do |uc|
36
+ X_SIZE.times do |x|
37
+ Y_SIZE.times do |y|
38
+ uc.add(@unit.new(table=self, x, y))
39
+ end
40
+ end
41
+ end
42
+ end
43
+
44
+ module Error
45
+ class TableError < StandardError
46
+ def message
47
+ 'Unit is not available.'
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end