Dive Into Python 3の覆面算をRubyで書いてみた
はじめに
最近、必要に迫られてDive Into Python 3を読んでPythonの勉強をしているわけですが、その第8章で出てきた覆面算のコードをRubyで書いてみた。
実装
以下の通りです。なるべくオリジナルに近づけたつもり。
# encoding: utf-8 DOCUMENT = <<EOS Find solutions to alphametic equations. > Alphametics.solve("SEND + MORE == MONEY") "9567 + 1085 == 10652" EOS module Alphametics def solve(puzzle) words = puzzle.upcase.scan(/[A-Z]+/) unique_characters = words.join.split("").uniq raise "Too many letters" unless unique_characters.size <= 10 first_letters = words.map{|word| word.slice(0)}.uniq n = first_letters.size characters = (first_letters + (unique_characters - first_letters)).join solution = (0..9).to_a.permutation(characters.length) do |guess| next if guess.slice(0, n).include?(0) equation = puzzle.tr(characters, guess.join) break equation if eval(equation) end solution if solution.instance_of?(String) end module_function :solve end if $0 == __FILE__ puts DOCUMENT and return if ARGV.size.zero? ARGV.each do |puzzle| puts puzzle solution = Alphametics.solve(puzzle) puts solution unless solution.nil? end end
実行例
$ ruby alphametics.rb "SEND + MORE == MONEY" SEND + MORE == MONEY 9567 + 1085 == 10652
感想
Pythonは要素の重複を許さない「集合」というクラスがあるので、いちいち重複を取り除く必要がないのがいい。*1
でも、"".join(list)
とか見てると完全に逆だろって思う。*2
いや、あれか、レシーバーに対するメソッドの戻り値はレシーバーと同じ型でなければいけない、という思想なのか。