トランプゲーム「大貧民」(「大富豪」ともいいます)の場の札と手札が与えられた場合、次に出せるすべての手の組み合わせを出力する問題です。
ジョーカーがワイルドカードになっているので、それをどう処理するかが考えどころになります。ここではジョーカーが手札に含まれている場合の処理を別にしました。
class Card
Rank = %W(3 4 5 6 7 8 9 T J Q K A 2)
def initialize(str)
@value = str
@rank = (str == "Jo") ? 13 : Rank.index(str[1])
end
attr_reader :value, :rank
alias to_s value
end
module Daihinmin
module_function
def play(input)
table, hand = input.split(",")
return "-" unless hand
hand = hand.scan(/../).map { |c| Card.new(c) }
joker = hand.find {|c| c.value == "Jo"}
table = table.scan(/../).map { |c| Card.new(c) }
t_rank = table.map(&:rank).min
t_num = table.size
cs = hand.group_by(&:rank).select { |k, v| k > t_rank }.values
result = cs.select { |ary| ary.size >= t_num }
.flat_map { |ary| ary.combination(t_num).to_a }
if joker && t_num >= 2
result +=
cs.select { |ary| ary.size >= t_num - 1 && ary[0] != joker }
.flat_map {|ary|
ary.combination(t_num - 1).map { |cards| cards + [joker] }
}
end
result.empty? ? "-" : result.map(&:join).join(",")
end
end
if __FILE__ == $0
[
"DJ,",
"H7,HK",
"S3,D4D2",
"S9,C8H4",
"S6,S7STCK",
"H4,SAS8CKH6S4",
"ST,D6S8JoC7HQHAC2CK",
"SA,HAD6S8S6D3C4H2C5D4CKHQS7D5",
"S2,D8C9D6HQS7H4C6DTS5S6C7HAD4SQ",
"Jo,HAC8DJSJDTH2",
"S4Jo,CQS6C9DQH9S2D6S3",
"CTDT,S9C2D9D3JoC6DASJS4",
"H3D3,DQS2D6H9HAHTD7S6S7Jo",
"D5Jo,CQDAH8C6C9DQH7S2SJCKH5",
"C7H7,S7CTH8D5HACQS8JoD6SJS5H4",
"SAHA,S7SKCTS3H9DJHJH7S5H2DKDQS4",
"JoC8,H6D7C5S9CQH9STDTCAD9S5DAS2CT",
"HTST,SJHJDJCJJoS3D2",
"C7D7,S8D8JoCTDTD4CJ",
"DJSJ,DTDKDQHQJoC2",
"C3H3D3,CKH2DTD5H6S4CJS5C6H5S9CA",
"D8H8S8,CQHJCJJoHQ",
"H6D6S6,H8S8D8C8JoD2H2",
"JoD4H4,D3H3S3C3CADASAD2",
"DJHJSJ,SQDQJoHQCQC2CA",
"H3D3Jo,D4SKH6CTS8SAS2CQH4HAC5DADKD9",
"C3JoH3D3,S2S3H7HQCACTC2CKC6S7H5C7",
"H5C5S5D5,C7S6D6C3H7HAH6H4C6HQC9",
"H7S7C7D7,S5SAH5HAD5DAC5CA",
"D4H4S4C4,S6SAH6HAD6DAC6CAJo",
"DTCTSTHT,S3SQH3HQD3DQC3CQJo",
"JoS8D8H8,S9DTH9CTD9STC9CAC2"
].each do |input|
puts Daihinmin.play(input)
end
end
カードをどう表現するか迷って、ここではクラス化しました(Card
クラス)。カードのランクを数値化し、弱い順に 0 からの Integer を与えてあります(Card#rank
)。単独でいちばん強いジョーカーのランクは 13 です。String で表されるカードの表現はCard#value
で取得できます。
処理としては、まず場の札をtable
、手札をhand
とします。ジョーカーが存在すればjoker
に入ります(存在しなければnil
)。
手札をランクによってグループ化し、場の札のランク(t_rank
)よりランクの高いものだけを残したのがcs
です。
cs
から、場の札の枚数(t_num
)以上のものを残し、あとは場の札の枚数だけの組み合わせを取ってresult
に格納します。
手札にジョーカーがあり、かつ場の札の枚数(t_num
)が2枚以上の場合は、ジョーカーをワイルドカードとしながらさらに同様のことをします。
結果を String で表現する(Array#join を使っています)ため、Card#to_s
をCard#value
のエイリアスとして設定しています。
なお、出力は順序の不定性があるので、テストをサボっています(笑)。
#追記
テストも書いてみました。
if __FILE__ == $0
def same?(input, expect)
inputs = input.split(",")
expects = expect.split(",")
return false unless inputs.size == expects.size
equal = ->(a, b) {
a == b || a.scan(/../).sort == b.scan(/../).sort
}
is_found = ->(ans) {
s = expects.find { |e| equal.(e, ans) }
return false unless s
expects.delete(s)
true
}
inputs.all?(&is_found)
end
[
["DJ,", "-"],
["H7,HK", "HK"],
["S3,D4D2", "D4,D2"],
["S9,C8H4", "-"],
["S6,S7STCK", "CK,ST,S7"],
["H4,SAS8CKH6S4", "S8,CK,H6,SA"],
["ST,D6S8JoC7HQHAC2CK", "Jo,C2,CK,HA,HQ"],
["SA,HAD6S8S6D3C4H2C5D4CKHQS7D5", "H2"],
["S2,D8C9D6HQS7H4C6DTS5S6C7HAD4SQ", "-"],
["Jo,HAC8DJSJDTH2", "-"],
["S4Jo,CQS6C9DQH9S2D6S3", "DQCQ,D6S6,H9C9"],
["CTDT,S9C2D9D3JoC6DASJS4", "JoC2,SJJo,DAJo"],
["H3D3,DQS2D6H9HAHTD7S6S7Jo", "JoHA,JoD6,JoH9,D6S6,D7S7,JoS6,HTJo,JoDQ,S2Jo,JoD7,JoS7"],
["D5Jo,CQDAH8C6C9DQH7S2SJCKH5", "CQDQ"],
["C7H7,S7CTH8D5HACQS8JoD6SJS5H4", "HAJo,JoSJ,H8S8,H8Jo,CQJo,CTJo,JoS8"],
["SAHA,S7SKCTS3H9DJHJH7S5H2DKDQS4", "-"],
["JoC8,H6D7C5S9CQH9STDTCAD9S5DAS2CT", "CTDT,H9D9,S9D9,DACA,CTST,H9S9,DTST"],
["HTST,SJHJDJCJJoS3D2", "DJCJ,SJDJ,JoHJ,CJHJ,SJJo,HJSJ,DJJo,JoCJ,JoD2,SJCJ,DJHJ"],
["C7D7,S8D8JoCTDTD4CJ", "D8S8,JoS8,CTJo,DTJo,JoCJ,CTDT,D8Jo"],
["DJSJ,DTDKDQHQJoC2", "JoDK,HQDQ,DQJo,C2Jo,JoHQ"],
["C3H3D3,CKH2DTD5H6S4CJS5C6H5S9CA", "S5H5D5"],
["D8H8S8,CQHJCJJoHQ", "JoCQHQ,JoHJCJ"],
["H6D6S6,H8S8D8C8JoD2H2", "D2H2Jo,D8JoS8,D8S8C8,C8D8H8,JoC8S8,H8JoC8,S8H8C8,JoS8H8,C8JoD8,D8H8S8,D8JoH8"],
["JoD4H4,D3H3S3C3CADASAD2", "DACASA"],
["DJHJSJ,SQDQJoHQCQC2CA", "SQJoCQ,DQCQJo,JoSQHQ,SQCQHQ,DQHQSQ,HQDQCQ,HQDQJo,SQDQCQ,CQJoHQ,SQJoDQ"],
["H3D3Jo,D4SKH6CTS8SAS2CQH4HAC5DADKD9", "HASADA"],
["C3JoH3D3,S2S3H7HQCACTC2CKC6S7H5C7", "-"],
["H5C5S5D5,C7S6D6C3H7HAH6H4C6HQC9", "C6D6S6H6"],
["H7S7C7D7,S5SAH5HAD5DAC5CA", "SADACAHA"],
["D4H4S4C4,S6SAH6HAD6DAC6CAJo", "C6H6S6D6,SAJoDACA,S6H6C6Jo,SACAJoHA,HADASAJo,HADAJoCA,CADAHASA,D6C6JoH6,S6D6C6Jo,H6JoS6D6"],
["DTCTSTHT,S3SQH3HQD3DQC3CQJo", "HQSQJoDQ,SQCQDQJo,DQCQHQJo,SQHQJoCQ,CQDQHQSQ"],
["JoS8D8H8,S9DTH9CTD9STC9CAC2", "H9C9D9S9"],
].each do |input, expect|
p same? Daihinmin.play(input), expect
end
end