1
2
3
4 class Spiral
5 attr_accessor :row_num, :col_num, :direction
6
7 def initialize(m, n)
8 @spiral = []
9 @value = 0
10 @row_num = m
11 @col_num = n
12 @direction = :right
13 end
14
15 def get(row, col)
16 if (row < 0 || row >= row_num || col < 0 || col >= col_num)
17 raise RangeError.new("Out of Bound : row = #{row} col = #{col}")
18 end
19 @spiral[row] ||= Array.new
20 @spiral[row][col] ||= nil
21 @spiral[row][col]
22 end
23
24 def increment_fill(row, col)
25 @value += 1
26 fill(row, col, @value)
27 end
28
29 def fill(row, col, value)
30 if (row < 0 || row >= row_num || col < 0 || col >= col_num)
31 raise RangeError.new("Out of Bound : row = #{row} col = #{col}")
32 end
33 @spiral[row] ||= Array.new
34 @spiral[row][col] = value
35 end
36
37 def populate(x = 0, y = 0)
38 count = 0
39 while (1)
40 increment_fill(x, y)
41 count += 1
42
43 break if count == row_num * col_num
44 x, y = next_cell(x, y)
45 end
46 @spiral
47 end
48
49 def next_cell(row, col)
50 new_row = row
51 new_col = col
52
53 case @direction
54 when :right
55 new_col = col + 1
56 when :left
57 new_col = col - 1
58 when :down
59 new_row = row + 1
60 when :up
61 new_row = row - 1
62 end
63
64 if ((new_col >= col_num || new_col < 0))
65 change_direction
66 next_cell(row, col)
67 elsif ((new_row >= row_num || new_row < 0))
68 change_direction
69 next_cell(row, col)
70 elsif (get(new_row, new_col) != nil)
71 change_direction
72 next_cell(row, col)
73 else
74 return [new_row, new_col]
75 end
76 end
77
78 def change_direction
79 case @direction
80 when :right
81 @direction = :down
82 when :down
83 @direction = :left
84 when :left
85 @direction = :up
86 when :up
87 @direction = :right
88 else
89 raise ArgumentError.new("Illegal value for current_direction #{@direction}")
90 end
91 end
92
93 def dump
94 display = ''
95 @spiral.each do |row|
96 row.each do |col|
97 display << sprintf("%3d ", col)
98 end
99 display << "\n"
100 end
101 puts display
102 end
103 end
104
105 if $0 == __FILE__
106 s = Spiral.new(ARGV[1].to_i, ARGV[0].to_i)
107 s.populate
108 s.dump
109 end
110
1 $:.unshift File.join(File.dirname(__FILE__),'..','lib')
2
3 require 'test/unit'
4 require 'spiral'
5
6 class TestSpiral < Test::Unit::TestCase
7 def setup
8 @spiral = Spiral.new(4, 5)
9 end
10
11 def test_increment_fill_0_0_first
12 @spiral.increment_fill(0, 0)
13 assert_equal(1, @spiral.get(0, 0))
14 end
15
16 def test_increment_fill_1_1_first
17 @spiral.increment_fill(1, 1)
18 assert_equal(1, @spiral.get(1, 1))
19 end
20
21 def test_increment_fill_successive
22 @spiral.increment_fill(0,0)
23 @spiral.increment_fill(0,1)
24 @spiral.increment_fill(1,1)
25 assert_equal(3, @spiral.get(1, 1))
26 end
27
28 def test_get_beyond_limit_raises_exception
29 assert_raise(RangeError) {
30 @spiral.get(@spiral.row_num + 1, @spiral.col_num + 1)
31 }
32 end
33
34 def test_get_below_zero_raises_exception
35 assert_raise(RangeError) {
36 @spiral.get(-1, 0)
37 }
38 end
39
40 def test_get_at_limit_raises_exception
41 assert_raise(RangeError) {
42 @spiral.get(@spiral.row_num, @spiral.col_num)
43 }
44 end
45
46
47 def test_unfill_get_with_in_range_does_not_raise_exception
48 assert_nothing_raised() {
49 @spiral.get(@spiral.row_num - 1, @spiral.col_num - 1)
50 }
51 end
52
53 def test_unfill_get_with_in_range_returns_nil
54 assert_equal(nil, @spiral.get(@spiral.row_num - 1, @spiral.col_num - 1))
55 end
56
57 def test_fill_beyond_range_raises_exception
58 assert_raise(RangeError) {
59 @spiral.increment_fill(@spiral.row_num + 1, @spiral.col_num + 1)
60 }
61 end
62
63 def test_fill_beyond_range_raises_exception
64 assert_raise(RangeError) {
65 @spiral.increment_fill(0, -1)
66 }
67 end
68
69 def test_fill_at_range_raises_exception
70 assert_raise(RangeError) {
71 @spiral.increment_fill(@spiral.row_num, @spiral.col_num)
72 }
73 end
74
75 def test_populate
76 spiral = [
77 [1, 2, 3, 4, 5],
78 [14, 15, 16, 17, 6],
79 [13, 20, 19, 18, 7],
80 [12, 11, 10, 9, 8]
81 ]
82 s = @spiral.populate
83 assert_equal(spiral, s)
84 end
85
86 def test_change_directon_right
87 @spiral.direction = :right
88 @spiral.change_direction
89 assert_equal(:down, @spiral.direction)
90 end
91
92 def test_change_directon_up
93 @spiral.direction = :up
94 @spiral.change_direction
95 assert_equal(:right, @spiral.direction)
96 end
97
98 def test_next_cell_0_0
99 x, y = @spiral.next_cell(0,0)
100 assert_equal(0, x)
101 assert_equal(1, y)
102 end
103
104 def test_next_cell_0_4
105 x, y = @spiral.next_cell(0,4)
106 assert_equal(1, x)
107 assert_equal(4, y)
108 end
109
110 end
111