Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- module Rudoku
- class Sudoku
- attr_reader :fields
- def initialize
- @fields = Array.new(9 * 9) do |i|
- x = i % 9
- y = i / 9
- Field.new(x, y)
- end
- end
- def [](*val) # 1-based
- if val.size == 2 # 2, 3
- x = val[0] - 1
- y = val[1] - 1
- elsif val.size == 1 # B3
- str = val[0].to_s
- x = str[0] - ?A
- y = str[1] - ?1
- else
- return nil
- end
- @fields[x + y * 9]
- end
- def []=(i, number) # also allows setting of multiple values: s[:B5] = [1, 2, 5]
- self[i].remove((1..9).to_a - number.to_a.flatten)
- end
- def solved?
- @fields.all? { |f| f.solved? }
- end
- def to_s
- row_strings = (1..9).collect { |i| row_to_s(i) }
- row_strings.join("\n-+-+-+-+-+-+-+-+-\n")
- end
- def row(i) # 1-based
- @fields[(9 * (i - 1))..(9 * (i - 1) + 8)]
- end
- def column(i) # 1-based
- @fields[(0..8).collect{ |j| 9 * j + i - 1}]
- end
- def grid(i) # 1-based
- # TODO
- end
- def row_to_s(i)
- (row(i).collect { |f| f.to_s }).join("|")
- end
- def each_row
- # TODO
- end
- def each_column
- # TODO
- end
- def each_grid
- # TODO
- end
- def apply_rule(rule)
- rule.apply_to(self)
- end
- end
- class Field
- attr_reader :possibilities, :x, :y
- def initialize(x,y)
- @possibilities = (1..9).to_a
- @x = x
- @y = y
- end
- def remove(numbers)
- numbers = numbers.to_a.flatten # this works for a single number and for ranges, too
- new_possibilities = @possibilities - numbers
- @possibilities = new_possibilities if (new_possibilities.size >= 1) # fails silently!
- end
- def position
- (?A + x).chr + (y + 1).to_s # 2, 3 => B3
- end
- def solved?
- @possibilities.size == 1
- end
- def to_s
- solved? ? @possibilities[0].to_s : " "
- end
- end
- class Rule
- attr_reader :salience
- def initialize(salience = 0, &block)
- @logic = block
- @salience = salience
- end
- def apply_to(sudoku)
- args_iterate(@logic.arity - 1) do |*args|
- @logic.call(sudoku, *args)
- end
- # applies the rule to the sudoku.
- # iterates over all possible values for all parameters (thats why they're kept in a hash)
- end
- protected
- def args_iterate(n) # n: number of arguments
- if n == 0
- yield
- else
- # fill in leftmost parameter, iterate over the remaining argumnents
- args_iterate(n - 1) do |*args|
- ret = false
- (1..9).each do |i|
- ret = yield(i, *args)
- break if ret # breaks out of all
- end
- ret # return value has to be passed on to the higher level
- end
- end
- end
- end
- class Solver
- attr_reader :rules
- def initialize(rules)
- @rules = rules
- end
- def sort_rules
- @rules = @rules.sort_by { |r| r.salience }.reverse # highest salience first
- end
- def solve(sudoku, allow_bruteforce = false)
- # if apply_rules returns true, no bruteforcing is required.
- return true if apply_rules(sudoku)
- return false unless allow_bruteforce
- bruteforce(sudoku)
- return true
- end
- def apply_rules(sudoku)
- # iterate over all implemented rules in order of saliency
- # if one is applicable and changes the sudoku, start over
- @rules.each do |rule|
- retry if rule.apply_to(sudoku) # true -> something has changed
- end
- sudoku.solved?
- end
- def bruteforce(sudoku)
- # TODO
- end
- end
- end
- include Rudoku
- =begin RULE BLOCK:
- heeft een aantal parameters, de eerste is het sudoku-object
- geeft "true" terug als er een aanpassing gebeurd is aan de sudoku
- =end
- s = Sudoku.new
- r = Rule.new do |s, i, j, k|
- puts i.to_s + "," + j.to_s + "," + k.to_s
- true if i == 3 && j == 5 && k == 2
- end
- r.apply_to(s)
- # test code
- =begin
- s = Rudoku::Field.new(2,3)
- puts s.position
- s.remove(1..9)
- puts s.possibilities
- s.remove(1..4)
- puts s.possibilities
- puts s.solved?
- s.remove(6..9)
- puts s.possibilities
- puts s.solved?
- s = Rudoku::Sudoku.new
- s[:B5] = [1,2,5]
- s[:A1] = 1
- s[:A2] = 2
- puts s
- =end
- # s.row(3).each do |f|
- # puts f.position
- # end
- # puts s[9, 9].position
Add Comment
Please, Sign In to add comment