CodeIQ「中学入試から:正三角形?二等辺?」

CodeIQ の鍋谷武典さん出題の問題を解いてみた。
問題と解説はこちら。
「中学入試から:正三角形?二等辺?」の、解説・解題

解説を読んでから気づいたんだけど、ちょっと今回は力尽くなコードを書いてしまった。
言語は Ruby
v.values - [nil] のところは v.values.compact のほうが良いというアドバイスを頂いた。
すぐに実行できるものを http://ideone.com/VJUSuo に置いておいた。

#! ruby -Ku
# データは 'data.utf8.txt' から読み込む
require 'mathn'

# v[0], v[1], v[2] の間で成立している独立な等式の数
# 例えば v[0]=v[1]=v[2] のとき 2 を返し、v[0]=v[1]≠v[2] のとき 1 を返す
def n_equalities(v)
  a = v.values - [nil]
  a.size - a.uniq.size
end

# 問題を解き、あ,い,う のいずれかを返す
def solve(angle, edge)
  # このメソッドの戻り値は下の permutation が生成する順列の順序に依らない
  %w(A B C).permutation do |i, j, k|
    angle[i] = angle[j] if edge[i] && edge[i] == edge[j] && angle[j]
    angle[i] = 90 - angle[k] / 2 if edge[i] && edge[i] == edge[j] && angle[k]
    angle[k] = 180 - angle[i] - angle[j] if angle[i] && angle[j]
  end
  return %w(う い あ)[[n_equalities(angle), n_equalities(edge)].max]
end

def extract_values(data)
  # 例えば "角A=60度" のとき angle['A'] = 60
  # "AB=10cm" のとき edge['C'] = 10 (辺には向かい合う角と同じ記号をあてる)
  angle, edge = {}, {}
  data.split(',').each do |d|
    if d =~ /^([ABC])=(\d+)$/ then
      angle[$1] = $2.to_i
    elsif d =~ /^([ABC])([ABC])=(\d+)cm$/ then
      edge[(%w(A B C) - [$1, $2])[0]] = $3.to_i
    else
      fail 'illegal data'
    end
  end
  [angle, edge]
end

open('data.utf8.txt') do |file|
  file.each do |line|
    id, data, expected = line.chomp.split("\t")
    angle, edge = extract_values(data)
    answer = solve(angle, edge)
    # 求めた答が用意されたものと合わないとき、
    # id, 用意された答, 求めた答, 問題 を出力
    puts "#{id} #{expected} #{answer}  '#{data}'" unless expected == answer
  end
end