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