Implemented backtracking algorithm
This commit is contained in:
parent
c8ee8c311e
commit
ce935b9a1a
4 changed files with 57 additions and 14 deletions
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -71,7 +71,7 @@ module Sudoku
|
|||
}.join("\n")
|
||||
end
|
||||
|
||||
def solved?
|
||||
def complete?
|
||||
@grid.flatten.none? { |i| i == nil }
|
||||
end
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue