Verbal Arithmetic (#128)
class VerbalArithmetic def initialize(expr) parse(expr) analys end attr_reader :factor, :sum, :table private def parse(expr) term = expr.scan(/\w+/) unless expr.count('=') == 1 && (expr.count('+') + 2) == term.length raise AugmentError, "syntax error: #{expr}" end @factors = term[0,(expr.count('+') + 1)] @sum = term.last end def make_chars @chars =[] (@factors + [@sum]).each do |f| f.scan(/./).each do |c| @chars << c unless @chars.include?(c) end end raise AugmentError, "too many character: #{@expr}" unless @chars.length =< 10 end def analys make_chars backtrack([],(0..9).to_a) end def backtrack(table,rest) return calc(table) if table.length == @chars.length r = rest.each do |i| break if backtrack((table + [i]), (rest - [i])) end r == nil end def calc(t) first_is_zero = (@factors + [@sum]).inject(false) do|r,s| r or (t[@chars.index(s.slice(/./))] == 0) end return false if first_is_zero fs_sum = @factors.inject(0) do |r,s| r + s.scan(/./).map do |c| t[@chars.index(c)].to_s end.join.to_i end sum = @sum.scan(/./).map {|c| t[@chars.index(c)].to_s }.join.to_i return false unless fs_sum == sum @table = Hash[*(@chars.zip(t).flatten)] end end VerbalArithmetic.new(ARGV[0]).table.each do |k,v| puts "#{k}: #{v}" end
構文解析適当。