139 lines
3.7 KiB
Python
139 lines
3.7 KiB
Python
def suit_to_value(suit):
|
|
return {
|
|
"2": 2,
|
|
"3": 3,
|
|
"4": 4,
|
|
"5": 5,
|
|
"6": 6,
|
|
"7": 7,
|
|
"8": 8,
|
|
"9": 9,
|
|
"T": 10,
|
|
"J": 11,
|
|
"Q": 12,
|
|
"K": 13,
|
|
"A": 14,
|
|
}[suit]
|
|
|
|
|
|
assert(suit_to_value('K') == 13)
|
|
|
|
|
|
def is_flush(colors):
|
|
first_color = colors[0]
|
|
for color in colors:
|
|
if color != first_color:
|
|
return False
|
|
return True
|
|
|
|
|
|
assert(is_flush(["H", "H", "H", "H", "H"]))
|
|
assert(is_flush(["H", "H", "D", "H", "H"]) is False)
|
|
|
|
|
|
def is_straight(suits):
|
|
suits = sorted(suits)
|
|
first_suit = suits[0]
|
|
for suit in suits[1:]:
|
|
if first_suit + 1 != suit:
|
|
return False
|
|
first_suit = suit
|
|
return True
|
|
|
|
|
|
assert(is_straight([6, 3, 4, 5, 7]))
|
|
assert(is_straight([6, 3, 4, 5, 8]) is False)
|
|
|
|
|
|
def get_numbered_groups(ns):
|
|
""" Takes [0, 3, 0, 3, 1] and returns
|
|
[(2, 3), (2, 0), (1, 1)]
|
|
"""
|
|
rs = []
|
|
current_group = []
|
|
for n in sorted(ns, reverse=True):
|
|
if not current_group or n in current_group:
|
|
current_group.append(n)
|
|
else:
|
|
rs.append(current_group)
|
|
current_group = [n]
|
|
rs.append(current_group)
|
|
rs = sorted([(len(r), r[0]) for r in rs], reverse=True)
|
|
return rs
|
|
|
|
|
|
assert(get_numbered_groups([0, 3, 0, 3, 1]) == [(2, 3), (2, 0), (1, 1)])
|
|
|
|
|
|
def rank(hand):
|
|
""" A hand must be provided as a list of two letter strings.
|
|
The first letter is the suit and the second the suit of a card.
|
|
|
|
The function returns a tuple. The first value represents the hand as
|
|
an integer where 0 means high card and 9 means Straight Flush. The
|
|
second value is a list of integers ranking the value of the respective
|
|
rank. For example, a Royal Flush would be (9, [14, 13, 12, 11, 10]),
|
|
while 22aqj would be (1, [2, 2, 14, 12, 11]). By doing this we can
|
|
simply compare to hands by first comparing the rank itself and then
|
|
the list of integers.
|
|
|
|
We get something like ["5H", "6S", "7S", "5C", "KD"].
|
|
"""
|
|
|
|
suits, colors = zip(*(map(lambda s: (s[0], s[1]), hand)))
|
|
suits = sorted(map(suit_to_value, suits))
|
|
|
|
flush = is_flush(colors)
|
|
straight = is_straight(suits)
|
|
numbered_suits = get_numbered_groups(suits)
|
|
if flush and straight:
|
|
return [8, numbered_suits]
|
|
if flush:
|
|
return [5, numbered_suits]
|
|
if straight:
|
|
return [4, numbered_suits]
|
|
if numbered_suits[0][0] == 4:
|
|
return [7, numbered_suits]
|
|
if numbered_suits[0][0] == 3 and numbered_suits[1][0] == 2:
|
|
return [6, numbered_suits]
|
|
if numbered_suits[0][0] == 3:
|
|
return [3, numbered_suits]
|
|
if numbered_suits[0][0] == 2 and numbered_suits[1][0] == 2:
|
|
return [2, numbered_suits]
|
|
if numbered_suits[0][0] == 2:
|
|
return [1, numbered_suits]
|
|
return [0, numbered_suits]
|
|
|
|
|
|
def read_hands():
|
|
""" Reads a list of tuples where each field
|
|
in the tuple represents a hand.
|
|
"""
|
|
hands = []
|
|
with open("../txt/EulerProblem054.txt", "r") as f:
|
|
for line in f.readlines():
|
|
cards = line.strip().split(" ")
|
|
hands.append((cards[:5], cards[5:]))
|
|
return hands
|
|
|
|
|
|
def euler_054():
|
|
p1_wins = 0
|
|
|
|
for p1_hand, p2_hand in read_hands():
|
|
if rank(p1_hand) > rank(p2_hand):
|
|
p1_wins += 1
|
|
# msg = "P1 hand {} wins over P2 hand {}."
|
|
# print(msg.format(p1_hand, p2_hand))
|
|
else:
|
|
pass
|
|
# msg = "P1 hand {} loses versus P2 hand {}."
|
|
# print(msg.format(p1_hand, p2_hand))
|
|
|
|
return p1_wins
|
|
|
|
|
|
if __name__ == "__main__":
|
|
print("e054.py: " + str(euler_054()))
|
|
assert(euler_054() == 376)
|