rubyで数独 実装3
もう少し綺麗にできたから全体載せてリファクタリングは終了
class Sudoku def initialize @condition = Sudoku_condition.new @proc = 0 #debugで工程数を表示 end def solve(string) grid_new = make_grid(string) print_grid( solve_sub(grid_new) ) end private def solve_sub(grid, cur_cell=0) #cur_cellは現在のセル番号 return true if cur_cell > 80 print_debug(grid) #過程を見るため if grid[cur_cell] solve_sub(grid, cur_cell + 1) else for v in 1..9 grid[cur_cell] = v return grid if @condition.no_violation?(grid, cur_cell, v) && solve_sub(grid, cur_cell + 1) #再帰はスタックだから最後はここに来るのか、だから返り値はgridか end grid[cur_cell] = nil #1〜9まで試してどれもダメだったら end end def make_grid(string) # 空白と改行取り除いて、単語ごとに分解して、文字を数字に、ドットはnilに string.gsub(/[\s\n]/, '').split("").map do |num_c| num_c == "." ? nil : num_c.to_i end end def print_grid(grid) grid.each_slice(9).map do |arr| puts arr.join(" ") end end def print_debug(grid) print_grid(grid) puts "-------------------- #{@proc}" @proc += 1 # sleep(0.05) #ゆっくりみるため end end class Sudoku_condition def initialize end def no_violation?(grid, cur_cell, v) row_any?(grid, cur_cell, v) && column_any?(grid, cur_cell, v) && square_any?(grid, cur_cell, v) end private def row_any?(grid, cur_cell, v) r = cur_cell / 9 for i in 0..8 check_cell = 9 * r + i return false if check_cell != cur_cell and grid[check_cell] == v end end def column_any?(grid, cur_cell, v) c = cur_cell % 9 for i in 0..8 check_cell = 9 * i + c return false if check_cell != cur_cell and grid[check_cell] == v end end def square_any?(grid, cur_cell, v) r_base = (cur_cell / 9) / 3 * 3 #左上のマスの行と列 c_base = (cur_cell % 9) / 3 * 3 for i in 0..8 check_cell = 9 * (r_base + (i / 3)) + c_base + (i % 3) return false if check_cell != cur_cell and grid[check_cell] == v end end end line = "61....... .......27 4..6.8... .71...3.. 2385.6419 9641..75. 395.278.. 182.6.974 .468192.5" sudoku = Sudoku.new sudoku.solve(line)