どう書く: 参考問題1「ポーカー」

来月はひさしぶりにどう書くに参加するので、リハビリに参考問題1を解きました。Rubyで。

#!/usr/bin/ruby

def is_fourcards (cs)
    return cs.has_value?(4)
end

def is_threecards (cs)
    return cs.has_value?(3)
end

def cnt_pairs (cs)
    return cs.select {|k,v| v == 2}.length
end

input = ARGV[0]
ws = input.gsub(/10/,"T").split("")
cs = []
ws.each { |w| cs.push(w) unless /S|H|D|C/ =~ w }

nums = { }
(2..9).each { |n|
    nums[n.to_s] = 0
}
nums.update({"T" => 0, "J" => 0, "Q" => 0, "K" => 0, "A" => 0})
cs.each { |c|
    nums[c] = nums[c] + 1
}

result = "--"
if is_fourcards(nums) then
    rsult = "4K"
elsif is_threecards(nums) && cnt_pairs(nums) == 1 then
    result = "FH"
elsif is_threecards(nums) then
    result = "3K"
elsif cnt_pairs(nums) == 2 then
    result = "2P"
elsif cnt_pairs(nums) == 1 then
    result = "1P"
end
print result

最初、配列のeachメソッドを呼んでブロックを引数に渡し、ブロック外で定義したhashをブロック内で更新しようとしたら、毎回hashがリセットされてしまって悩みました。スコープ周りを理解してないかも。というか何も理解してないかも。

それはそうと、nidoさんの解答が3行だったので、ひっくり返りました。(ATNDのコメント欄で読めます)

以下、勉強になった点。

  • hashのキーに配列を使うという発想はなかった
  • トランプのsuitを区切り文字としてsplitするという発想はなかった
  • arrayオブジェクトのインデックスをrangeにするのはイディオム?
    • [1..-1]にしているのは、区切り文字が先頭にある場合に先頭要素が空白になるから? これって仕様?
  • group_byは便利