Guest User

Untitled

a guest
Dec 17th, 2017
72
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.84 KB | None | 0 0
  1. class Sudoku
  2. def initialize(board_string)
  3. @board = board_string.split("").map { |n| n.to_i }.each_slice(9).to_a
  4. row_col_each_with_index(@board) do |row_i, col_i, cell|
  5. @board[row_i][col_i] = (1..9).to_a if cell == 0
  6. end
  7. end
  8.  
  9. def solve!(board = @board)
  10. start_length = board.flatten.length
  11. check_board = remove_impossibles(dup_board(board))
  12. return false if (board = check_board) == false # Impossible state
  13.  
  14. if start_length == board.flatten.length # Stuck, start guessing
  15. next_board = try_guesses(board)
  16. else # Not stuck, keep solving
  17. next_board = solve!(dup_board(board))
  18. end
  19.  
  20. return board if board.flatten.length == 81 # Solved state
  21. @board = next_board
  22. end
  23.  
  24. def row_col_each_with_index(board)
  25. board.each_with_index do |row, row_i|
  26. row.each_with_index { |cell, col_i| yield(row_i, col_i, cell) }
  27. end
  28. end
  29.  
  30. def guess_list(board)
  31. guesses = {}
  32. row_col_each_with_index(board) do |row_i, col_i, cell|
  33. guesses[[row_i, col_i]] = cell if cell.is_a?(Array)
  34. end
  35. guesses
  36. end
  37.  
  38. def try_guesses(board)
  39. guesses = guess_list(board)
  40. until guesses.empty?
  41. next_board = solve!(make_guess_board(board, guesses))
  42. unless next_board == false
  43. return next_board
  44. end
  45. guesses.delete_if { |key, value| value.empty? }
  46. end
  47. false
  48. end
  49.  
  50. def make_guess_board(board, guesses)
  51. next_guess = guesses.first
  52. guess_board = dup_board(board)
  53. guess_board[next_guess[0][0]][next_guess[0][1]] = next_guess[1].pop
  54. guess_board
  55. end
  56.  
  57. def impossible?(row_i, col_i, num, board)
  58. row_include?(row_i, col_i, num, board) ||
  59. col_include?(row_i, col_i, num, board) ||
  60. box_include?(row_i, col_i, num, board)
  61. end
  62.  
  63. def col_include?(row_i, col_i, num, board)
  64. board.each_with_index do |row, test_row_i|
  65. next if row_i == test_row_i
  66. return true if row[col_i] == num
  67. end
  68. false
  69. end
  70.  
  71. def row_include?(row_i, col_i, num, board)
  72. board[row_i].each_with_index do |cell, test_col_i|
  73. next if col_i == test_col_i
  74. return true if cell == num
  75. end
  76. false
  77. end
  78.  
  79. def box_include?(row_i, col_i, num, board)
  80. box_range = box_range(row_i, col_i)
  81. box = board[box_range[0]].transpose[box_range[1]].transpose
  82. row_col_each_with_index(box) do |test_row_i, test_col_i, cell|
  83. next if row_i == (test_row_i + box_range[0].first) &&
  84. col_i == (test_col_i + box_range[1].first)
  85. return true if cell == num
  86. end
  87. false
  88. end
  89.  
  90. def box_range(row_i, col_i)
  91. row_start = (row_i / 3) * 3
  92. col_start = (col_i / 3) * 3
  93. [(row_start..row_start + 2), (col_start..col_start + 2)]
  94. end
  95.  
  96. def remove_impossibles(board)
  97. row_col_each_with_index(board) do |row_i, col_i, cell|
  98. if cell.is_a?(Array)
  99. cell.delete_if { |num| impossible?(row_i, col_i, num, board) }
  100. board[row_i][col_i] = cell.first if cell.length == 1
  101. return false if cell.empty?
  102. end
  103. return false if cell.is_a?(Integer) && impossible?(row_i, col_i, cell, board)
  104. end
  105. board
  106. end
  107.  
  108. def dup_board(board)
  109. Marshal.load(Marshal.dump(board)) # Duplicates array and all sub-arrays
  110. end
  111.  
  112. def print_board
  113. row_divider = "-------------------------\n"
  114. answer = ""
  115. return "Impossible board" unless @board.flatten.length == 81
  116. @board.each_with_index do |row, row_i|
  117. answer << "#{row_divider if row_i % 3 == 0}| "
  118. row.each_with_index do |cell, col_i|
  119. answer << "#{cell} #{'| ' if (col_i + 1) % 3 == 0}"
  120. end
  121. answer << "\n"
  122. end
  123. answer << "#{row_divider}\n"
  124. end
  125. end
  126. #------Driver Code-------
  127. boards = File.readlines('sample.unsolved.txt')
  128.  
  129. boards.each_with_index do |board_string, board_num|
  130. game = Sudoku.new(board_string.chomp)
  131. game.solve!
  132. puts "#{board_num + 1}"
  133. puts game.print_board
  134. end
Add Comment
Please, Sign In to add comment