I am currently completing a Sudoku solver in ruby. Using enumerator I have create a method that creates 9 arrays based on my 9x9 grid each of which refers to a 3x3 box in the sudoku game. Whilst testing this in Rspec I am finding that it only works in one test. When i create a second test using the same method it will always fail. When I muddle around they tests they work individually but not when the method is being called in a second test. I ideally want to add my method into my initialize method but this fails all tests apart from one. The error I get is 'StopIteration: iteration reached an end'. WHich I understand but why cant it just restart at each test? Any ideas?
class Grid
BoxOfIndex = [
0,0,0,1,1,1,2,2,2,0,0,0,1,1,1,2,2,2,0,0,0,1,1,1,2,2,2,
3,3,3,4,4,4,5,5,5,3,3,3,4,4,4,5,5,5,3,3,3,4,4,4,5,5,5,
6,6,6,7,7,7,8,8,8,6,6,6,7,7,7,8,8,8,6,6,6,7,7,7,8,8,8
].each
attr_accessor :cells, :rows, :columns, :boxes
def initialize(puzzle)
@cells = puzzle.split('').map {|v| Cell.new(v) }
create_boxes
end
def create_rows
@rows = cells.each_slice(9).to_a
end
def create_columns
@columns = create_rows.transpose
end
def create_boxes
@boxes = []
9.times { @boxes << Array.new}
@cells.each{|cell| @boxes[BoxOfIndex.next].concat([cell])}
end
....................Tests below(second test fails)
it "should be able to create boxes with a cell value" do
grid.create_boxes
expect(grid.boxes[0][2].value).to eq(5)
end
it "should be able to find neighbours of a cell" do
grid.create_boxes
end
I think the problem is that your BoxOfIndex
constant holds an iterator. In your create_boxes
method you iterate to the last element. Later specs cannot call next
again, because you already reached the end.
Change the constant to just hold the array:
BOX_OF_INDEX = [
0,0,0,1,1,1,2,2,2,0,0,0,1,1,1,2,2,2,0,0,0,1,1,1,2,2,2,
3,3,3,4,4,4,5,5,5,3,3,3,4,4,4,5,5,5,3,3,3,4,4,4,5,5,5,
6,6,6,7,7,7,8,8,8,6,6,6,7,7,7,8,8,8,6,6,6,7,7,7,8,8,8
]
And change the create_boxes
method to use a new iterator each time:
def create_boxes
@boxes = []
iterator = BOX_OF_INDEX.each
9.times { @boxes << Array.new }
@cells.each { |cell| @boxes[iterator.next].concat([cell]) }
end