Last active
August 29, 2015 14:09
-
-
Save tuwukee/de2dc102ec097234a15b to your computer and use it in GitHub Desktop.
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 SudokuBoard | |
def initialize(filename) | |
init_defaults() | |
@boards = parse_file(filename) | |
@solved = [] | |
@boards.each do |board| | |
solved_board = solve(parse_board(board)) | |
@solved.push solved_board | |
display(solved_board) | |
end | |
end | |
def print_result_to(filename) | |
begin | |
file = File.open(filename, 'w') | |
@solved.each do |board| | |
file.write("#{board.values.join('')}\n") | |
end | |
rescue IOError => e | |
puts "ERROR: can't write to file" | |
ensure | |
file.close unless file == nil | |
end | |
end | |
private | |
def parse_file(filename) | |
file = File.read(filename) | |
file.split(/[=]+\r?\n/).inject([]) do |boards,board| | |
boards.push board.gsub!(/\n/, '') | |
end | |
end | |
def merge(str1, str2) | |
line = [] | |
str1.each_char {|x| str2.each_char {|y| line.push (x + y) } } | |
line | |
end | |
def init_defaults | |
@digits = '123456789' | |
@cols = @digits | |
@rows = @digits | |
@cells = merge(@rows, @cols) | |
@vertical = [] | |
@horizontal = [] | |
@cubes = [] | |
@units = {} | |
@scope = {} | |
@cols.each_char {|c| @vertical.push merge(@rows, c)} | |
@rows.each_char {|r| @horizontal.push merge(r, @cols)} | |
cube_triples = @digits.scan(/.../) | |
cube_triples.each do |vl| | |
cube_triples.each do |hl| | |
@cubes.push merge(vl,hl) | |
end | |
end | |
opts = @vertical + @horizontal + @cubes | |
@cells.each do |c| | |
opts.each do |u| | |
if u.include?(c) | |
@units[c] ||= [] | |
@units[c].push u | |
end | |
end | |
@scope[c] = (@units[c].flatten - [c]).uniq | |
end | |
end | |
def board_values(board) | |
chars = [] | |
board_hash = {} | |
board.each_char do |c| | |
chars.push c if(@digits.include?(c) || '0._'.include?(c)) | |
end | |
@cells.zip(chars).each {|c| board_hash[c[0]] = c[1]} | |
board_hash | |
end | |
def nominate(board, cl, c) | |
vals = board[cl].gsub(c, '') | |
calls = [] | |
vals.each_char do |c2| | |
calls.push exclude(board, cl, c2) | |
end | |
calls.all? ? board : false | |
end | |
def display(board) | |
lines = board.values.each_slice(9) | |
lines.each do |line| | |
puts line.join('') | |
end | |
puts '='*9 | |
end | |
def exclude(board, cl, c) | |
return board unless board[cl].include?(c) | |
board[cl] = board[cl].gsub(c,'') | |
size = board[cl].size | |
if size == 0 | |
return false | |
elsif size == 1 | |
c2 = board[cl] | |
return false unless @scope[cl].inject([]){|temp, cl2| temp.push exclude(board, cl2, c2)}.all? | |
end | |
@units[cl].each do |u| | |
vals = u.select {|x| x if board[x].include?(c) } | |
size = vals.size | |
return false if(size == 0 || (size == 1 && !nominate(board, vals[0], c))) | |
end | |
board | |
end | |
def parse_board(initial_board) | |
board = {} | |
@cells.each do |c| | |
board[c] = @digits | |
end | |
board_values(initial_board).each do |key, val| | |
return false if(@digits.include?(val) && !nominate(board, key, val)) | |
end | |
board | |
end | |
def solve(board) | |
return false unless board | |
sizes = [] | |
temp = {} | |
@cells.each do |c| | |
size = board[c].size | |
sizes.push size == 1 | |
temp[c] = size if size > 1 | |
end | |
return board if sizes.all? | |
min_val = temp.min_by{|k,v| v} | |
results = [] | |
board[min_val[0]].each_char do |c| | |
x = solve(nominate(board.clone, min_val[0], c)) | |
return x if x | |
end | |
false | |
end | |
end | |
board = SudokuBoard.new('test2.txt') | |
board.print_result_to('result.txt') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
crazy