Problem 54
トランプのポーカーには(中略)。
プレーヤー1が勝つ手はいくつあるか。
http://projecteuler.net/index.php?section=problems&id=54
速度に問題はないので、どのようにすればきれいに書けるかを考えます。
上の役から順にあてはまっているかどうか判定すればいいのですが、そうすると例えばストレートフラッシュとフラッシュで2回同じ判定をしなければならないなどのムダがあって美しくありません。
まずは、フラッシュかそうでないかで分けます。
フラッシュでない場合は、ワンペアとかツーペアの役を判定します。辞書を使って同じ値のカードの枚数を数えます。例えば、
"2H 8S 3H 8D 2S" -> [ (8, 2), (2, 2), (3, 1) ]
とします。この際に値が大きい順にソートしておきます。これで用意に役が判定できます。タプルが5つあったら、あとはストレートかどうかの判定をします。
役の大きさを表す番号をつけておき、ツーペアなら2とします。そして、役が同じであるときの判定のために先ほどのタプルの2番目を取り出して配列にします。
[ (8, 2), (2, 2), (3, 1) ] -> [ 8, 2, 3 ]
これで簡単に勝負の判定ができるでしょう。
def all(f, a):
for e in filter(lambda e: not f(e), a):
return False
return Truedef unzip(a):
return [ e[0] for e in a ], [ e[1] for e in a ]def numerize(c):
return 2 + "23456789TJQKA".index(c)def make_hands(s):
def split(s): return (numerize(s[0]), s[1])
a = s.split(' ')
return (map(split, a[:5]), map(split, a[5:]))def read_hands():
file = open("poker.txt")
a = map(make_hands, file.readlines())
file.close()
return adef is_flush(suits):
return all(lambda e: e == suits[0], suits[1:])def is_straight(values):
return all(lambda k: values[k] == values[k+1] + 1, range(4))def add_dic(dic, key):
if key in dic:
dic[key] += 1
else:
dic[key] = 1def collect_same_values(values):
dic = { }
for n in values:
add_dic(dic, n)
a = list(dic.iteritems())
a.sort(key = lambda e: -e[0] - e[1] * 15)
return adef rank(h):
values, suits = unzip(h)
values.sort(key = lambda a: -a)
if is_flush(suits):
if is_straight(values):
if values[0] == 14:
return [ 9 ] + values # Royal Flush
else:
return [ 8 ] + values # Straight Flush
else:
return [ 5 ] + values # Flush
else:
a = collect_same_values(values)
values = map(lambda e: e[0], a)
if len(a) == 2:
if a[0][1] == 4:
return [ 7 ] + values # Four of a Kind
else:
return [ 6 ] + values # Full House
elif len(a) == 3:
if a[0][1] == 3:
return [ 3 ] + values # Three of a Kind
else:
return [ 2 ] + values # Two Pairs
elif len(a) == 4:
return [ 1 ] + values # One Pair
else:
if is_straight(values):
return [ 4 ] + values # Straight
else:
return [ 0 ] + values # High Carddef greater_hand(h1, h2):
r1 = rank(h1)
r2 = rank(h2)
for v1, v2 in zip(r1, r2):
if v1 != v2:
return v1 > v2
return Falseprint sum(map(lambda t: greater_hand(t[0], t[1]), read_hands()))