史上最大のなんとかかんとか
あなたのスキルで飯は食えるか? 史上最大のコーディングスキル判定だそうです。*1
ちょっとやってみました。
開始時間をちゃんと見てなかった…2時間くらい?
一応動いてるんじゃないかな…
3(4)5 みたいな真ん中待つ手があるの忘れてました……
#!/usr/bin/ruby class ManzInternal @@manz = Hash.new def self.create(input) @@manz[input] ||= ManzInternal.new(input) unless input.empty? end def initialize(input) @input_str = input @input_ary = input.split(//) @input_ary_uniq = @input_ary.uniq end def single @single ||= @input_ary_uniq.inject({}) { |res, k| res[k] = self.class.create(@input_str.sub(k, '')) res } end def pair @pair ||= (@input_ary.size < 2) ? {} : self.single.inject({}) { |res, (k, v)| res[k + k] = self.class.create(v.delete(k)) if v.include?(k) res } end def three @three ||= (@input_ary.size < 3) ? {} : self.pair.inject({}) { |res, (k, v)| k1 = k[0, 1] res[k + k1] = self.class.create(v.delete(k1)) if v.include?(k1) res } end def straight @straight ||= search_straight(3) end def half_straight @half_straight ||= search_straight(2).merge(search_straight(2, 2)) end def search_straight(len, step = 1) straight = Hash.new if len <= @input_ary.size v = @input_ary_uniq.join first = @input_ary_uniq[0].to_i last = @input_ary_uniq[-1].to_i - (len - 1) * step (first..last).each do |i| range = (0...len).inject([]) { |r, j| r << (i + j * step) } k = range.join straight[k] = self.class.create(range.inject(@input_str) { |r, j| r.sub(j.to_s, '') }) if v.include?(k) end end straight end def to_a @input_ary end def to_s @input_str end def inspect '#<%s:"%s">' % [ self.class, @input_str ] end def include?(str) @input_str.include? str end def delete(str) to_s.sub(str, '') end def all_by_types { :single => self.single, :pair => self.pair, :three => self.three, :straight => self.straight, :half_straight => self.half_straight } end protected def internal_search(set, count, searched, result, &block) self.all_by_types.each do |type, data| data.each do |k, manz| new_count = count.merge(type => k) { |_, a, b| a.dup << b } next if 1 < new_count[:single].size || 2 < new_count[:pair].size + new_count[:half_straight].size || 1 < new_count[:half_straight].size new_set = (set + [k]).sort unless searched.include?(search_key = new_set.hash) if manz manz.internal_search(new_set, new_count, searched, result, &block) else result << to_win(new_count) block.call(result.last) if block end searched[search_key] = true end end end end private def to_win(count) type = (1 == count[:single].size) ? :single : (2 == count[:pair].size) ? :pair : (1 == count[:half_straight].size) ? :half_straight : nil raise 'invalid set. (%s)' % count.values.flatten.join(')(') unless type '(%s)[%s]' % [ count.reject { |t, k| type == t }.values.flatten.sort.join(')('), count[type].join('][') ] end end class Manz < ManzInternal def initialize(input) raise 'Require 13 numbers 1 to 9.' unless /^[1-9]{13}$/ =~ input.to_s super input.to_s.split(//).sort.join end def search(&block) set = [] count = self.all_by_types.keys.inject({}) { |r, type| r[type] = []; r } searched = {} result = [] internal_search(set, count, searched, result, &block) result end end input = ARGV[0] || $stdin.gets Manz.new(input).search do |win| print win + "\n" end
修正前との差分
--- manz.rb.orig 2010-04-18 06:52:14.000000000 +0900 +++ manz.rb 2010-04-18 06:55:49.000000000 +0900 @@ -9,10 +9,11 @@ def initialize(input) @input_str = input @input_ary = input.split(//) + @input_ary_uniq = @input_ary.uniq end def single - @single ||= @input_ary.uniq.inject({}) { |res, k| + @single ||= @input_ary_uniq.inject({}) { |res, k| res[k] = self.class.create(@input_str.sub(k, '')) res } @@ -38,16 +39,18 @@ end def half_straight - @half_straight ||= search_straight(2) + @half_straight ||= search_straight(2).merge(search_straight(2, 2)) end - def search_straight(len) + def search_straight(len, step = 1) straight = Hash.new if len <= @input_ary.size - v = self.single.keys.sort.join - (1..7).each do |i| - range = (i...i+len) - k = range.to_a.join + v = @input_ary_uniq.join + first = @input_ary_uniq[0].to_i + last = @input_ary_uniq[-1].to_i - (len - 1) * step + (first..last).each do |i| + range = (0...len).inject([]) { |r, j| r << (i + j * step) } + k = range.join straight[k] = self.class.create(range.inject(@input_str) { |r, j| r.sub(j.to_s, '') }) if v.include?(k) end end
*1:飯を食えるかどうかはスキルに関係ないよね、日本って…