Guest User

Untitled

a guest
Mar 14th, 2018
70
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.55 KB | None | 0 0
  1. module Rudoku
  2. class Sudoku
  3. attr_reader :fields
  4.  
  5. def initialize
  6. @fields = Array.new(9 * 9) do |i|
  7. x = i % 9
  8. y = i / 9
  9. Field.new(x, y)
  10. end
  11. end
  12.  
  13. def [](*val) # 1-based
  14. if val.size == 2 # 2, 3
  15. x = val[0] - 1
  16. y = val[1] - 1
  17. elsif val.size == 1 # B3
  18. str = val[0].to_s
  19. x = str[0] - ?A
  20. y = str[1] - ?1
  21. else
  22. return nil
  23. end
  24.  
  25. @fields[x + y * 9]
  26. end
  27.  
  28. def []=(i, number) # also allows setting of multiple values: s[:B5] = [1, 2, 5]
  29. self[i].remove((1..9).to_a - number.to_a.flatten)
  30. end
  31.  
  32. def solved?
  33. @fields.all? { |f| f.solved? }
  34. end
  35.  
  36. def to_s
  37. row_strings = (1..9).collect { |i| row_to_s(i) }
  38. row_strings.join("\n-+-+-+-+-+-+-+-+-\n")
  39. end
  40.  
  41. def row(i) # 1-based
  42. @fields[(9 * (i - 1))..(9 * (i - 1) + 8)]
  43. end
  44.  
  45. def column(i) # 1-based
  46. @fields[(0..8).collect{ |j| 9 * j + i - 1}]
  47. end
  48.  
  49. def grid(i) # 1-based
  50. # TODO
  51. end
  52.  
  53. def row_to_s(i)
  54. (row(i).collect { |f| f.to_s }).join("|")
  55. end
  56.  
  57.  
  58. def each_row
  59. # TODO
  60. end
  61.  
  62. def each_column
  63. # TODO
  64. end
  65.  
  66. def each_grid
  67. # TODO
  68. end
  69.  
  70.  
  71. def apply_rule(rule)
  72. rule.apply_to(self)
  73. end
  74. end
  75.  
  76. class Field
  77. attr_reader :possibilities, :x, :y
  78.  
  79. def initialize(x,y)
  80. @possibilities = (1..9).to_a
  81. @x = x
  82. @y = y
  83. end
  84.  
  85. def remove(numbers)
  86. numbers = numbers.to_a.flatten # this works for a single number and for ranges, too
  87. new_possibilities = @possibilities - numbers
  88. @possibilities = new_possibilities if (new_possibilities.size >= 1) # fails silently!
  89. end
  90.  
  91. def position
  92. (?A + x).chr + (y + 1).to_s # 2, 3 => B3
  93. end
  94.  
  95. def solved?
  96. @possibilities.size == 1
  97. end
  98.  
  99. def to_s
  100. solved? ? @possibilities[0].to_s : " "
  101. end
  102. end
  103.  
  104. class Rule
  105. attr_reader :salience
  106.  
  107. def initialize(salience = 0, &block)
  108. @logic = block
  109. @salience = salience
  110. end
  111.  
  112. def apply_to(sudoku)
  113. args_iterate(@logic.arity - 1) do |*args|
  114. @logic.call(sudoku, *args)
  115. end
  116. # applies the rule to the sudoku.
  117. # iterates over all possible values for all parameters (thats why they're kept in a hash)
  118. end
  119.  
  120. protected
  121. def args_iterate(n) # n: number of arguments
  122. if n == 0
  123. yield
  124. else
  125. # fill in leftmost parameter, iterate over the remaining argumnents
  126. args_iterate(n - 1) do |*args|
  127. ret = false
  128. (1..9).each do |i|
  129. ret = yield(i, *args)
  130. break if ret # breaks out of all
  131. end
  132.  
  133. ret # return value has to be passed on to the higher level
  134. end
  135. end
  136. end
  137. end
  138.  
  139. class Solver
  140. attr_reader :rules
  141.  
  142. def initialize(rules)
  143. @rules = rules
  144. end
  145.  
  146. def sort_rules
  147. @rules = @rules.sort_by { |r| r.salience }.reverse # highest salience first
  148. end
  149.  
  150. def solve(sudoku, allow_bruteforce = false)
  151. # if apply_rules returns true, no bruteforcing is required.
  152. return true if apply_rules(sudoku)
  153. return false unless allow_bruteforce
  154. bruteforce(sudoku)
  155. return true
  156. end
  157.  
  158. def apply_rules(sudoku)
  159. # iterate over all implemented rules in order of saliency
  160. # if one is applicable and changes the sudoku, start over
  161. @rules.each do |rule|
  162. retry if rule.apply_to(sudoku) # true -> something has changed
  163. end
  164.  
  165. sudoku.solved?
  166. end
  167.  
  168. def bruteforce(sudoku)
  169. # TODO
  170. end
  171. end
  172. end
  173.  
  174.  
  175.  
  176. include Rudoku
  177.  
  178. =begin RULE BLOCK:
  179. heeft een aantal parameters, de eerste is het sudoku-object
  180. geeft "true" terug als er een aanpassing gebeurd is aan de sudoku
  181. =end
  182.  
  183.  
  184. s = Sudoku.new
  185. r = Rule.new do |s, i, j, k|
  186. puts i.to_s + "," + j.to_s + "," + k.to_s
  187. true if i == 3 && j == 5 && k == 2
  188. end
  189.  
  190. r.apply_to(s)
  191.  
  192. # test code
  193. =begin
  194. s = Rudoku::Field.new(2,3)
  195. puts s.position
  196. s.remove(1..9)
  197. puts s.possibilities
  198. s.remove(1..4)
  199. puts s.possibilities
  200. puts s.solved?
  201. s.remove(6..9)
  202. puts s.possibilities
  203. puts s.solved?
  204.  
  205.  
  206. s = Rudoku::Sudoku.new
  207. s[:B5] = [1,2,5]
  208. s[:A1] = 1
  209. s[:A2] = 2
  210. puts s
  211. =end
  212.  
  213. # s.row(3).each do |f|
  214. # puts f.position
  215. # end
  216.  
  217. # puts s[9, 9].position
Add Comment
Please, Sign In to add comment