Ka Mok Ka Mok - 4 months ago 7
Ruby Question

How to refactor consecutive, independent, if statements in this algorithm?

The following method generates 81

Cell
objects that each have their distinct
row
,
column
, and
blocks
. It uses an algorithm that changes those attributes based on the
Cell
that's currently be generated.

The
1.times do
portion is implemented to skip that block of
if
statements on the first loop inside the
until
loop, when the
cell_counter
is 0. How do I make this more elegant?

def initialize_default_cells
cell_counter, row, column = 0,0,0
block = 1

until cell_counter == 81
1.times do
break if cell_counter == 0
if cell_counter % 1 == 0
column += 1
end
if cell_counter % 3 == 0
block += 1
end
if cell_counter % 9 == 0
column -= 9
row += 1
block -= 3
end
if cell_counter % 27 == 0
block += 3
end
end
@cells << Cell.new(ROW_ID[row], COLUMN_ID[column], block)
cell_counter += 1
end
end

Answer

I concluded that it was easiest to calculate row, column and block from scratch for each i = 0,..,80.

def initialize_default_cells
  (0..80).each do |i|
    @cells << Cell.new(ROW_ID[i/9], COLUMN_ID[i%9], 1 + (i%9)/3 + 3*(i/27))
  end
end

The key for COLUMN_ID (i%9) is reduced from i-9*(i/9) and the last argument (1 + (i%9)/3 + 3*(i/27)) is reduced from 1 + i/3 - 3*(i/9) + 3*(i/27)

Consider three examples.

i=0

@cells << Cell.new(ROW_ID[0/9], COLUMN_ID[0%9], 1 + (0%9)/3 + 3*(0/27))
  #=> << Cell.new(ROW_ID[0], COLUMN_ID[0], 1)

i=6

@cells << Cell.new(ROW_ID[6/9], COLUMN_ID[6%9], 1 + (6%9)/3 + 3*(6/27))
  #=> << Cell.new(ROW_ID[0], COLUMN_ID[6], 3)

i=29

@cells << Cell.new(ROW_ID[29/9], COLUMN_ID[29%9], 1 + (29%9)/3 + 3*(29/27))
  # << Cell.new(ROW_ID[3], COLUMN_ID[2], 4)

When i=6, 6/3 #=> 2 is the number of positive numbers that are divisible by 3, 6/9 #=> 0 is the number of positive numbers that are divisible by 9 and 6/27 #=> 0 is the number of positive numbers that are divisible by 27. The arguments of Cell::new are then computed with these values.

Comments