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

備忘としてのメモを記載

rubyで数独 実装

前回のruby数独の本を参考に実装したもの。
自分が読みやすいように書き換えたり、クラスを導入したりした。
Sudoku_conditionクラスの中身は読むのすら面倒だったから本の内容そのまま。
ここ読むだけでもこの本のコードがどのくらい読みにくいかわかると思う。

class Sudoku
  def initialize
    @condition = Sudoku_condition.new
  end

  def solve(string)
    grid_new = make_grid(string)
    grid_solved = solve_sub(grid_new, 0)
    print_grid(grid_solved)
  end
  
  private
  def solve_sub(grid, p) #pは現在のセル番号
    return true if p > 80
    print_debug(grid,p) #過程を見るため
    if grid[p]
      solve_sub(grid, p + 1)
    else
      for v in 1..9
        grid[p] = v
        return true if @condition.no_violation?(grid, p) && solve_sub(grid, p + 1)
      end
      grid[p] = nil #1〜9まで試してどれもダメだったら
      return false
    end
  end

  def make_grid(string)
    string.gsub!(/[\s\n]/, '')
    string.split("").map { |num_c| num_c == "." ? nil : num_c.to_i }
  end

  def print_grid(grid)
    grid.each_slice(9).map do |arr|
      puts arr.join(" ")
    end
  end

  def print_debug(grid,p)
    print_grid(grid)
    puts "-------------------- #{p}"
    sleep(0.05) #ゆっくりみるため
  end
end

class Sudoku_condition
  def initialize
  end

  def no_violation?(grid, p)
    (block_is_ok?(row(grid, p)) &&
    block_is_ok?(column(grid, p)) &&
    block_is_ok?(square(grid, p)))
  end

  private
  def row(grid, p)
    grid[9 * (p / 9), 9]
  end

  def column(grid, p)
    (0..8).map { |k| grid[9 * k + p % 9] }
  end

  def square(grid, p)
    (0..8).map { |k| grid[9 * (3 * (p / 9 / 3) + (k / 3)) + 3 * (p % 9 / 3) + (k % 3)] }
  end

  def block_is_ok?(block)
    unique?(block.compact)
  end

  def unique?(list)
    (list.length == list.uniq.length)
  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)