コーディングスキル判定の麻雀問題を解いてみた
2010年04月06日
こちら(makeplex salon:あなたのスキルで飯は食えるか? 史上最大のコーディングスキル判定 (1/2) – ITmedia エンタープライズ)の麻雀問題を Ruby で解いてみた。
以前やった迷路探索問題(人生を書き換える者すらいた。: 人材獲得作戦・4 試験問題ほか)の作者の問題らしい。
Gauche 穴掘り法で迷路作成
最短経路探索プログラムの試験問題を解いてみた
麻雀に詳しくないのでクラス名・変数名がおかしいかも。
結果の牌の組み合わせを Machi
クラスとして MachiList
クラスに保存していく。
Machi
クラスには刻子・順子・アタマ・待ちをそれぞれインスタンス変数として別々に保持する。
check
メソッドで残り牌の数を調べながら処理を振り分けている。
### 待ち class Machi attr_accessor :kantsu, :juntsu, :atama, :machi def initialize(machi = nil) if machi.nil? @kantsu = [] @juntsu = [] @atama = "" @machi = "" else @kantsu = Array.new(machi.kantsu) @juntsu = Array.new(machi.juntsu) @atama = machi.atama @machi = machi.machi end end # 自身と machi との同一性チェック def has_same?(machi) if (@kantsu.sort <=> machi.kantsu.sort) == 0 and (@juntsu.sort <=> machi.juntsu.sort) == 0 and @atama == machi.atama and @machi == machi.machi return true else return false end end # データを配列にする # 待ち牌は [] で囲む def to_a return @kantsu.sort.concat(@juntsu.sort) << (@atama) << "[#{@machi}]" end end ### 待ちリスト class MachiList attr_accessor :list def initialize @list = [] end # リストに待ちを追加する # 追加時に同一性チェックをする def add(machi) if is_unique?(machi) @list << machi end end # リストを印字する def print_list @list.each do |m| m.to_a.each do |s| if s.match(/^\d+$/) print "(#{s})" else print "#{s}" end end print "\n" end end # 待ちを探す def check(data, machi) c = count_rest(data) case c when 0 self.add(machi) when 1 1.upto(9).each do |i| if data[i] > 0 tmp_mdata = Array.new(data) tmp_mmachi = Machi.new(machi) tmp_mdata[i] -= 1 tmp_mmachi.machi = "#{i}" check(tmp_mdata, tmp_mmachi) end end when 2 check_machi(data, machi) when 4 check_kantsu(data, machi) check_juntsu(data, machi) check_atama(data, machi) else check_kantsu(data, machi) check_juntsu(data, machi) end end private # 刻子 def check_kantsu(data, machi) 1.upto(9).each do |i| if has_kantsu?(i, data) tmp_kdata = Array.new(data) tmp_kdata[i] -= 3 tmp_kmachi = Machi.new(machi) tmp_kmachi.kantsu << "#{i}#{i}#{i}" check(tmp_kdata, tmp_kmachi) end end end # 順子 def check_juntsu(data, machi) 1.upto(9).each do |i| if has_juntsu?(i, data) tmp_jdata = Array.new(data) tmp_jdata[i] -= 1 tmp_jdata[i+1] -= 1 tmp_jdata[i+2] -= 1 tmp_jmachi = Machi.new(machi) tmp_jmachi.juntsu << "#{i}#{i+1}#{i+2}" check(tmp_jdata, tmp_jmachi) end end end # アタマ def check_atama(data, machi) 1.upto(9).each do |i| if has_atama?(i, data) tmp_adata = Array.new(data) tmp_adata[i] -= 2 tmp_amachi = Machi.new(machi) tmp_amachi.atama = "#{i}#{i}" check(tmp_adata, tmp_amachi) end end end # 待ち def check_machi(data, machi) 1.upto(9).each do |i| tmp_mdata = Array.new(data) tmp_mmachi = Machi.new(machi) if data[i] > 1 tmp_mdata[i] -= 2 tmp_mmachi.machi = "#{i}#{i}" check(tmp_mdata, tmp_mmachi) elsif data[i+1] and data[i] > 0 and data[i+1] > 0 tmp_mdata[i] -= 1 tmp_mdata[i+1] -= 1 tmp_mmachi.machi = "#{i}#{i+1}" check(tmp_mdata, tmp_mmachi) elsif data[i+2] and data[i] > 0 and data[i+2] > 0 tmp_mdata[i] -= 1 tmp_mdata[i+2] -= 1 tmp_mmachi.machi = "#{i}#{i+2}" check(tmp_mdata, tmp_mmachi) end end end # 刻子の候補を持っているかどうか def has_kantsu?(i, ary) ary[i] > 2 end # 順子の候補を持っているかどうか def has_juntsu?(i, ary) if i < 8 ary[i] > 0 and ary[i+1] > 0 and ary[i+2] > 0 else false end end # アタマの候補を持っているかどうか def has_atama?(i, ary) ary[i] > 1 end # 残り牌の数を調べる def count_rest(ary) count = 0 1.upto(9).each do |i| if ary[i] > 0 count += ary[i] end end count end # 重複する待ちがないかどうかをチェック def is_unique?(machi) @list.each do |m| if m.has_same?(machi) return false end end return true end end ### ここからテスト def str2num_array(str) ret_array = Array.new(10, 0) str.each_char do |c| ret_array[c.to_i] += 1 end ret_array end def test(str) machilist = MachiList.new machi = Machi.new machilist.check(str2num_array(str), machi) machilist.print_list end haipai_list = [ "1112224588899", "1122335556799", "1112223335559", "1223344888999", "1112345678999" ] haipai_list.each do |str| p str test(str) puts "------------------------------" end
実行結果
"1112224588899" (111)(222)(888)(99)[45] ------------------------------ "1122335556799" (555)(123)(123)(99)[67] (123)(123)(567)(55)[99] (123)(123)(567)(99)[55] ------------------------------ "1112223335559" (111)(222)(333)(555)[9] (555)(123)(123)(123)[9] ------------------------------ "1223344888999" (888)(999)(123)(234)[4] (888)(999)(123)(44)[23] (888)(999)(234)(234)[1] ------------------------------ "1112345678999" (111)(999)(234)(567)[8] (111)(999)(234)(678)[5] (111)(999)(345)(678)[2] (111)(234)(567)(99)[89] (111)(234)(789)(99)[56] (111)(456)(789)(99)[23] (999)(123)(456)(11)[78] (999)(123)(678)(11)[45] (999)(345)(678)(11)[12] (123)(456)(789)(11)[99] (123)(456)(789)(99)[11] ------------------------------
プログラミング言語 Ruby
posted with amazlet at 10.04.06
まつもと ゆきひろ David Flanagan
オライリージャパン
売り上げランキング: 91254
オライリージャパン
売り上げランキング: 91254