Implemented backtracking algorithm

This commit is contained in:
Alberto Venturini 2019-11-02 15:17:12 +02:00
parent c8ee8c311e
commit ce935b9a1a
4 changed files with 57 additions and 14 deletions

View file

@ -64,11 +64,11 @@ describe Sudoku::Board do
"...3"
end
it "should not be solved if it's not solved" do
it "should not be complete if there are nulls" do
board = Sudoku::Board.new(4, 2)
(0..3).each { |i| board.put(i, i, i) }
board.solved?.should be_false
board.complete?.should be_false
end

View file

@ -17,17 +17,16 @@ describe Sudoku::Parser do
board = Sudoku::Parser.parse(board_string, block_size: 3)
Sudoku::Solver.solve(board)
true
# board.to_s.should eq \
# "812753649\n" \
# "943682175\n" \
# "675491283\n" \
# "154237896\n" \
# "369845721\n" \
# "287169534\n" \
# "521974368\n" \
# "438526917\n" \
# "796318452"
board.to_s.should eq \
"812753649\n" \
"943682175\n" \
"675491283\n" \
"154237896\n" \
"369845721\n" \
"287169534\n" \
"521974368\n" \
"438526917\n" \
"796318452"
end

View file

@ -71,7 +71,7 @@ module Sudoku
}.join("\n")
end
def solved?
def complete?
@grid.flatten.none? { |i| i == nil }
end

View file

@ -2,6 +2,50 @@ module Sudoku
class Solver
def self.solve(board)
solve_rec(board, find_next_nil(board, 0))
end
# Simple solver with backtracking
private def self.solve_rec(board, index)
if board.complete?
true
else
coords = index_to_coordinates(board, index)
x = coords[:x]
y = coords[:y]
result = (1..board.size).any? { |v|
board.valid?(v, x, y) && begin
board.put(v, x, y)
solve_rec(board, find_next_nil(board, index))
end
}
if !result
board.put(nil, x, y)
end
result
end
end
private def self.find_next_nil(board, index)
max = (board.size ** 2) - 1
new_index = (index..max).find(-1) { |i|
coords = index_to_coordinates(board, i)
board.get(coords[:x], coords[:y]) == nil
}
new_index
end
private def self.coordinates_to_index(board, x, y)
y * board.size + x
end
private def self.index_to_coordinates(board, index : Int32)
{ x: index % board.size, y: index // board.size }
end
end