院卒新人サラリーマンのメモ代わり

備忘としてのメモを記載

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)