toy 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 +7 -0
- data/.document +4 -0
- data/.gitignore +19 -0
- data/.rspec +1 -0
- data/.travis.yml +8 -0
- data/ChangeLog.md +3 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +46 -0
- data/LICENSE.txt +20 -0
- data/README.md +49 -0
- data/Rakefile +41 -0
- data/bin/toy +7 -0
- data/lib/toy.rb +9 -0
- data/lib/toy/controller.rb +99 -0
- data/lib/toy/direction.rb +38 -0
- data/lib/toy/robot.rb +66 -0
- data/lib/toy/table.rb +52 -0
- data/lib/toy/unit.rb +44 -0
- data/lib/toy/unit_collection.rb +62 -0
- data/lib/toy/version.rb +5 -0
- data/spec/controller_spec.rb +162 -0
- data/spec/direction_spec.rb +35 -0
- data/spec/robot_spec.rb +143 -0
- data/spec/spec_helper.rb +8 -0
- data/spec/table_spec.rb +37 -0
- data/spec/toy_spec.rb +9 -0
- data/spec/unit_collection_spec.rb +125 -0
- data/spec/unit_spec.rb +67 -0
- data/toy.gemspec +24 -0
- metadata +136 -0
data/lib/toy/unit.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Toy
|
4
|
+
class Unit
|
5
|
+
attr_reader :table, :x, :y, :object
|
6
|
+
|
7
|
+
def initialize(table=Table.new, x, y)
|
8
|
+
raise Error::CoordinateError unless x.is_a?(Fixnum)
|
9
|
+
raise Error::CoordinateError unless y.is_a?(Fixnum)
|
10
|
+
raise Error::TableError unless table.is_a?(Table)
|
11
|
+
|
12
|
+
@table = table
|
13
|
+
@x = x
|
14
|
+
@y = y
|
15
|
+
@object = nil
|
16
|
+
end
|
17
|
+
|
18
|
+
def hold!(object)
|
19
|
+
@object = object
|
20
|
+
end
|
21
|
+
|
22
|
+
def release!
|
23
|
+
@object = nil
|
24
|
+
end
|
25
|
+
|
26
|
+
def available?
|
27
|
+
@object.nil?
|
28
|
+
end
|
29
|
+
|
30
|
+
module Error
|
31
|
+
class CoordinateError < ArgumentError
|
32
|
+
def message
|
33
|
+
'Coordinates must be of type Fixnum!'
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class TableError < ArgumentError
|
38
|
+
def message
|
39
|
+
'Table must be of type Table!'
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Toy
|
4
|
+
class UnitCollection
|
5
|
+
attr_reader :all
|
6
|
+
|
7
|
+
def initialize(direction=Toy::Direction)
|
8
|
+
@all = []
|
9
|
+
@direction = direction
|
10
|
+
end
|
11
|
+
|
12
|
+
def add(unit)
|
13
|
+
raise Error::UnitError unless unit.is_a?(Unit)
|
14
|
+
|
15
|
+
@all << unit
|
16
|
+
end
|
17
|
+
|
18
|
+
def find_by_coordinates(x, y)
|
19
|
+
@all.find { |unit| unit.x == x && unit.y == y }
|
20
|
+
end
|
21
|
+
|
22
|
+
def find_by_object(object)
|
23
|
+
@all.find { |unit| unit.object == object }
|
24
|
+
end
|
25
|
+
|
26
|
+
def find_north_of(x, y)
|
27
|
+
@all.find { |unit| unit.x == x && unit.y == y.succ }
|
28
|
+
end
|
29
|
+
|
30
|
+
def find_east_of(x, y)
|
31
|
+
@all.find { |unit| unit.x == x.succ && unit.y == y }
|
32
|
+
end
|
33
|
+
|
34
|
+
def find_south_of(x, y)
|
35
|
+
@all.find { |unit| unit.x == x && unit.y == y.pred }
|
36
|
+
end
|
37
|
+
|
38
|
+
def find_west_of(x, y)
|
39
|
+
@all.find { |unit| unit.x == x.pred && unit.y == y }
|
40
|
+
end
|
41
|
+
|
42
|
+
def find_by_direction_of(x, y, direction)
|
43
|
+
raise Error::DirectionError unless @direction::DIRECTION.include?(direction)
|
44
|
+
|
45
|
+
send("find_#{direction}_of", x, y)
|
46
|
+
end
|
47
|
+
|
48
|
+
module Error
|
49
|
+
class UnitError < ArgumentError
|
50
|
+
def message
|
51
|
+
'Argument must be of type Unit!'
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
class DirectionError < ArgumentError
|
56
|
+
def message
|
57
|
+
'Invalid direction!'
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
data/lib/toy/version.rb
ADDED
@@ -0,0 +1,162 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe Toy::Controller do
|
6
|
+
let(:controller) { Toy::Controller.new }
|
7
|
+
|
8
|
+
describe '#start' do
|
9
|
+
context 'on invalid command' do
|
10
|
+
before { allow(controller).to receive(:gets).and_return('INVALID', 'STOP') }
|
11
|
+
|
12
|
+
specify do
|
13
|
+
expect { controller.start }.to output("Invalid command! Type HELP for list of available commands.\n").to_stdout
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
context 'on HELP' do
|
18
|
+
before { allow(controller).to receive(:gets).and_return('HELP', 'STOP') }
|
19
|
+
|
20
|
+
specify do
|
21
|
+
expect { controller.start }.to output("Available commands: STOP HELP PLACE MOVE LEFT RIGHT REPORT\n").to_stdout
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'on PLACE' do
|
26
|
+
context 'when valid arguments' do
|
27
|
+
before { allow(controller).to receive(:gets).and_return('PLACE 1,1,NORTH', 'STOP') }
|
28
|
+
|
29
|
+
specify do
|
30
|
+
controller.start
|
31
|
+
expect(controller.robot.position).to eq([1, 1, :north])
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context 'when invalid coordinates' do
|
36
|
+
before { allow(controller).to receive(:gets).and_return('PLACE 1,INVALID,NORTH', 'STOP') }
|
37
|
+
|
38
|
+
specify do
|
39
|
+
expect { controller.start }.to output("Coordinates must be of type Fixnum!\n").to_stdout
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context 'when invalid direciton' do
|
44
|
+
before { allow(controller).to receive(:gets).and_return('PLACE 1,1,INVALID', 'STOP') }
|
45
|
+
|
46
|
+
specify do
|
47
|
+
expect { controller.start }.to output("Invalid direction!\n").to_stdout
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context 'when invalid arguments' do
|
52
|
+
before { allow(controller).to receive(:gets).and_return('PLACE 1,INVALID', 'STOP') }
|
53
|
+
|
54
|
+
specify do
|
55
|
+
expect { controller.start }.to output("Invalid placement arguments!\n").to_stdout
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
context 'when unit is taken' do
|
60
|
+
before { allow(controller).to receive(:gets).and_return('PLACE 1,1,NORTH','PLACE 1,1,NORTH', 'STOP') }
|
61
|
+
|
62
|
+
specify do
|
63
|
+
expect { controller.start }.to output("Not available!\n").to_stdout
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context 'when unit is not non-existant' do
|
68
|
+
before { allow(controller).to receive(:gets).and_return('PLACE 12,12,NORTH', 'STOP') }
|
69
|
+
|
70
|
+
specify do
|
71
|
+
expect { controller.start }.to output("Not available!\n").to_stdout
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
context 'on MOVE' do
|
77
|
+
before { allow(controller).to receive(:gets).and_return('MOVE', 'STOP') }
|
78
|
+
|
79
|
+
context 'when placed' do
|
80
|
+
context 'when unit is available' do
|
81
|
+
before { controller.robot.place(0, 0, :north) }
|
82
|
+
|
83
|
+
specify do
|
84
|
+
controller.start
|
85
|
+
expect(controller.robot.position).to eq([0, 1, :north])
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
context 'when unit is not available' do
|
90
|
+
before { controller.robot.place(0, 0, :south) }
|
91
|
+
|
92
|
+
specify do
|
93
|
+
controller.start
|
94
|
+
expect(controller.robot.position).to eq([0, 0, :south])
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
context 'when not placed' do
|
100
|
+
specify do
|
101
|
+
expect { controller.start }.to output("Robot is not placed!\n").to_stdout
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
context 'on LEFT' do
|
107
|
+
before { allow(controller).to receive(:gets).and_return('LEFT', 'STOP') }
|
108
|
+
|
109
|
+
context 'when placed' do
|
110
|
+
before { controller.robot.place(0, 0, :north) }
|
111
|
+
|
112
|
+
specify do
|
113
|
+
controller.start
|
114
|
+
expect(controller.robot.facing).to eq(:west)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
context 'when not placed' do
|
119
|
+
specify do
|
120
|
+
expect { controller.start }.to output("Robot is not placed!\n").to_stdout
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
context 'on RIGHT' do
|
126
|
+
before { allow(controller).to receive(:gets).and_return('RIGHT', 'STOP') }
|
127
|
+
|
128
|
+
context 'when placed' do
|
129
|
+
before { controller.robot.place(0, 0, :north) }
|
130
|
+
|
131
|
+
specify do
|
132
|
+
controller.start
|
133
|
+
expect(controller.robot.facing).to eq(:east)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
context 'when not placed' do
|
138
|
+
specify do
|
139
|
+
expect { controller.start }.to output("Robot is not placed!\n").to_stdout
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
context 'on REPORT' do
|
145
|
+
before { allow(controller).to receive(:gets).and_return('REPORT', 'STOP') }
|
146
|
+
|
147
|
+
context 'when placed' do
|
148
|
+
before { controller.robot.place(0, 0, :north) }
|
149
|
+
|
150
|
+
specify do
|
151
|
+
expect { controller.start }.to output("0,0,NORTH\n").to_stdout
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
context 'when not placed' do
|
156
|
+
specify do
|
157
|
+
expect { controller.start }.to output("Robot is not placed!\n").to_stdout
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe Toy::Direction do
|
6
|
+
let(:direction) { Toy::Direction }
|
7
|
+
|
8
|
+
describe '.rotate_left' do
|
9
|
+
context 'when valid arguments' do
|
10
|
+
specify { expect(direction.rotate_left(:north)).to eq(:west) }
|
11
|
+
specify { expect(direction.rotate_left(:east)).to eq(:north) }
|
12
|
+
end
|
13
|
+
|
14
|
+
context 'when invalid arguments' do
|
15
|
+
specify do
|
16
|
+
expect { direction.rotate_left(:invalid) }.to \
|
17
|
+
raise_error Toy::Direction::Error::DirectionError, 'Invalid direction!'
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '.rotate_right' do
|
23
|
+
context 'when valid arguments' do
|
24
|
+
specify { expect(direction.rotate_right(:west)).to eq(:north) }
|
25
|
+
specify { expect(direction.rotate_right(:east)).to eq(:south) }
|
26
|
+
end
|
27
|
+
|
28
|
+
context 'when invalid arguments' do
|
29
|
+
specify do
|
30
|
+
expect { direction.rotate_right(:invalid) }.to \
|
31
|
+
raise_error Toy::Direction::Error::DirectionError, 'Invalid direction!'
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/spec/robot_spec.rb
ADDED
@@ -0,0 +1,143 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe Toy::Robot do
|
6
|
+
let(:robot) { Toy::Robot.new }
|
7
|
+
|
8
|
+
describe '#facing' do
|
9
|
+
context 'when placed' do
|
10
|
+
before { robot.place(0, 0, :north) }
|
11
|
+
|
12
|
+
specify { expect(robot.facing).to eq(:north) }
|
13
|
+
end
|
14
|
+
|
15
|
+
context 'when not placed' do
|
16
|
+
specify { expect(robot.facing).to eq(nil) }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '#table' do
|
21
|
+
specify { expect(robot.table.is_a?(Table)).to eq(true) }
|
22
|
+
end
|
23
|
+
|
24
|
+
describe '#place' do
|
25
|
+
context 'when valid arguments' do
|
26
|
+
before { robot.place(0, 0, :north) }
|
27
|
+
|
28
|
+
specify { expect(robot.facing).to eq(:north) }
|
29
|
+
specify { expect(robot.position).to eq([0, 0, :north]) }
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'when invalid direction' do
|
33
|
+
specify do
|
34
|
+
expect { robot.place(0, 0, :invalid) }.to \
|
35
|
+
raise_error Toy::Direction::Error::DirectionError, 'Invalid direction!'
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context 'when invalid coordinate' do
|
40
|
+
specify do
|
41
|
+
expect { robot.place(:invalid, 0, :north) }.to \
|
42
|
+
raise_error(Toy::Unit::Error::CoordinateError, 'Coordinates must be of type Fixnum!')
|
43
|
+
end
|
44
|
+
|
45
|
+
specify do
|
46
|
+
expect { robot.place(0, :invalid, :north) }.to \
|
47
|
+
raise_error(Toy::Unit::Error::CoordinateError, 'Coordinates must be of type Fixnum!')
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe '#placed?' do
|
53
|
+
context 'when placed' do
|
54
|
+
before { robot.place(0, 0, :north) }
|
55
|
+
|
56
|
+
specify { expect(robot.placed?).to eq(true) }
|
57
|
+
end
|
58
|
+
|
59
|
+
context 'when not placed' do
|
60
|
+
specify { expect(robot.placed?).to eq(false) }
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe '#position' do
|
65
|
+
context 'when placed' do
|
66
|
+
before { robot.place(0, 0, :north) }
|
67
|
+
|
68
|
+
specify { expect(robot.position).to eq([0, 0, :north]) }
|
69
|
+
end
|
70
|
+
|
71
|
+
context 'when not placed' do
|
72
|
+
specify do
|
73
|
+
expect { robot.position }.to \
|
74
|
+
raise_error(Toy::Robot::Error::PlacementError, 'Robot is not placed!')
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe '#move!' do
|
80
|
+
context 'when placed' do
|
81
|
+
context 'when target unit is available' do
|
82
|
+
before do
|
83
|
+
robot.place(0, 0, :north)
|
84
|
+
robot.move!
|
85
|
+
end
|
86
|
+
|
87
|
+
specify { expect(robot.position).to eq([0, 1, :north]) }
|
88
|
+
end
|
89
|
+
|
90
|
+
context 'when target unit is not available' do
|
91
|
+
before do
|
92
|
+
robot.place(0, 0, :south)
|
93
|
+
robot.move!
|
94
|
+
end
|
95
|
+
|
96
|
+
specify { expect(robot.position).to eq([0, 0, :south]) }
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
context 'when not placed' do
|
101
|
+
specify do
|
102
|
+
expect { robot.move! }.to \
|
103
|
+
raise_error(Toy::Robot::Error::PlacementError, 'Robot is not placed!')
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
describe '#turn_left!' do
|
109
|
+
context 'when placed' do
|
110
|
+
before do
|
111
|
+
robot.place(0, 0, :north)
|
112
|
+
robot.turn_left!
|
113
|
+
end
|
114
|
+
|
115
|
+
specify { expect(robot.position).to eq([0, 0, :west]) }
|
116
|
+
end
|
117
|
+
|
118
|
+
context 'when not placed' do
|
119
|
+
specify do
|
120
|
+
expect { robot.turn_left! }.to \
|
121
|
+
raise_error(Toy::Robot::Error::PlacementError, 'Robot is not placed!')
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
describe '#turn_right!' do
|
127
|
+
context 'when placed' do
|
128
|
+
before do
|
129
|
+
robot.place(0, 0, :north)
|
130
|
+
robot.turn_right!
|
131
|
+
end
|
132
|
+
|
133
|
+
specify { expect(robot.position).to eq([0, 0, :east]) }
|
134
|
+
end
|
135
|
+
|
136
|
+
context 'when not placed' do
|
137
|
+
specify do
|
138
|
+
expect { robot.turn_right! }.to \
|
139
|
+
raise_error(Toy::Robot::Error::PlacementError, 'Robot is not placed!')
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|