Last active
August 29, 2015 14:05
-
-
Save audibleblink/393c28766ed5fbd5349e to your computer and use it in GitHub Desktop.
Easy-level solver for sudoku
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Sudoku | |
def initialize(board_string) | |
@board = board_string.split("") | |
end | |
def solve! | |
return self if solved? | |
board.each_with_index do |cell, cell_index| | |
# next unless cell == '0' | |
replace_cell_if_only_answer_at cell_index if cell == "0" | |
end | |
solve! # did this instead of #until because I prefer a dead stack to an infinite loop, just in case | |
end | |
private | |
attr_accessor :board # made this private because I never need to call #board outside this class | |
def solved? | |
!board.include?('0') | |
end | |
def replace_cell_if_only_answer_at index | |
candidates = possible_answers_at index | |
board[index] = candidates.first if candidates.length == 1 | |
end | |
def possible_answers_at index | |
#useful article on array manipulation http://blog.endpoint.com/2011/06/using-set-operators-with-ruby-arrays.html | |
[*"1".."9"] - ( row(index) | col(index) | box(index) ) | |
end | |
# These methods return a single array from | |
# their collections for a given spot on the board | |
def row index | |
rows[index / 9] | |
end | |
def col index | |
columns[index % 9] | |
end | |
def box index | |
boxes[ find_box_index_for(index) ] | |
end | |
# These methods return 2D arrays of our board's | |
# rows, columns and boxes | |
def rows | |
board.each_slice(9).to_a | |
end | |
def columns | |
board.each_slice(9).to_a.transpose | |
end | |
def boxes | |
boxes = Array.new(9) { Array.new } | |
board.each_with_index do |cell, cell_index| | |
boxes[ find_box_index_for(cell_index) ].push cell | |
end | |
boxes | |
end | |
def find_box_index_for index | |
(index / 9 / 3 * 3) + (index % 9 / 3) | |
end | |
def to_s | |
board.each_slice(9).to_a.map { |row| row.join(' ') }.join("\n") | |
end | |
end | |
# The file has newlines at the end of each line, so we call | |
# String#chomp to remove them. | |
board_string = File.readlines('sample.unsolved.txt').first.chomp | |
puzzle = Sudoku.new(board_string) | |
puts puzzle.solve! |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment