史上がなんとかの面妖な問題といた。

makeplex salon:あなたのスキルで飯は食えるか? 史上最大のコーディングスキル判定 (1/2) - ITmedia エンタープライズ

ニコニコ市場をついついシジョウと読んじゃう派です。そのおかげか3時間以内にはできました。

class Tehai
  attr_reader :hai, :red

  def initialize(hai)
    @hai = hai.gsub(/\s/, "").each_char.map(&:to_i).sort
    @red = []
  end

  def yaku(type)
    a = {:koku=>[1,1,1],:jun=>[1,2,3],:zu=>[1,1],
      :toi=>[1,1],:ryan=>[1,2],:kan=>[1,3],:tan=>[1]}[type]

    (9-(a[-1]-a[0])).times{|i|
      hai = @hai.dup
      b = a.map{|e|e+i}.each{|e|
        if i = hai.index(e)
          hai.delete_at(i)
        end
      }

      if hai.size == @hai.size - a.size
        @hai = hai
        @red << [type, b]
        return b
      end
    }
    nil
  end

  def reduce(syms)
    syms.each{|s| yaku(s)}
    @red
  end
end

def all_syms
  return @all_syms if @all_syms

  ret = []
  [:toi,:ryan,:kan].each{|e|
    a = [:zu,e] + [:jun]*3 + [:koku]*3
    ret += a.permutation(5).to_a
  }
  a = [:tan] + [:jun]*4 + [:koku]*4
  ret += a.permutation(5).to_a

  @all_syms = ret.uniq
end

def mati(s)
  ret = []

  all_syms.each{|syms|
    hai = Tehai.new(s)
    next unless (r = hai.reduce(syms)).size == 5
    mt = r.select{|e|
      [:toi,:ryan,:kan,:tan].include?(e[0])
    }
    raise unless mt.size == 1
    mt = mt[0]
    r.delete(mt)
    te = r.transpose[1]
    ret << te.sort.map{|e|"(#{e.join})"}.join+" [#{mt[1].join}]"
  }
  ret.uniq
end

require 'pp'

pp mati("1112224588899"), ""
pp mati("1122335556799"), ""
pp mati("1112223335559"), ""
pp mati("1223344888999"), ""
pp mati("1112345678999"), ""