137 lines
5.1 KiB
Python
137 lines
5.1 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Created on 27 Sep 2021
|
|
|
|
@author: David Doblas Jiménez
|
|
@email: daviddoji@pm.me
|
|
|
|
Solution for problem 54 of Project Euler
|
|
https://projecteuler.net/problem=54
|
|
"""
|
|
|
|
from pathlib import Path
|
|
from utils import timeit
|
|
|
|
|
|
@timeit("Problem 54")
|
|
def compute():
|
|
"""
|
|
In the card game poker, a hand consists of five cards and are ranked,
|
|
from lowest to highest, in the following way:
|
|
|
|
High Card: Highest value card.
|
|
One Pair: Two cards of the same value.
|
|
Two Pairs: Two different pairs.
|
|
Three of a Kind: Three cards of the same value.
|
|
Straight: All cards are consecutive values.
|
|
Flush: All cards of the same suit.
|
|
Full House: Three of a kind and a pair.
|
|
Four of a Kind: Four cards of the same value.
|
|
Straight Flush: All cards are consecutive values of same suit.
|
|
Royal Flush: Ten, Jack, Queen, King, Ace, in same suit.
|
|
|
|
The cards are valued in the order:
|
|
|
|
2, 3, 4, 5, 6, 7, 8, 9, 10, Jack, Queen, King, Ace.
|
|
|
|
If two players have the same ranked hands then the rank made up of the
|
|
highest value wins; for example, a pair of eights beats a pair of fives
|
|
(see example 1 below). But if two ranks tie, for example, both players
|
|
have a pair of queens, then highest cards in each hand are compared
|
|
(see example 4 below); if the highest cards tie then the next highest
|
|
cards are compared, and so on.
|
|
|
|
Consider the following five hands dealt to two players:
|
|
|
|
Hand Player 1 Player 2 Winner
|
|
1 5H 5C 6S 7S KD 2C 3S 8S 8D TD Player 2
|
|
Pair of Fives Pair of Eights
|
|
2 5D 8C 9S JS AC 2C 5C 7D 8S QH Player 1
|
|
Highest card Ace Highest card Queen
|
|
3 2D 9C AS AH AC 3D 6D 7D TD QD Player 2
|
|
Three Aces Flush with Diamonds
|
|
4 4D 6S 9H QH QC 3D 6D 7H QD QS Player 1
|
|
Pair of Queens Pair of Queens
|
|
Highest card Nine Highest card Seven
|
|
5 2H 2D 4C 4D 4S 3C 3D 3S 9S 9D Player 1
|
|
Full House Full House
|
|
With Three Fours with Three Threes
|
|
|
|
The file, poker.txt, contains one-thousand random hands dealt to two
|
|
players. Each line of the file contains ten cards (separated by a single
|
|
space): the first five are Player 1's cards and the last five are Player
|
|
2's cards. You can assume that all hands are valid (no invalid characters
|
|
or repeated cards), each player's hand is in no specific order, and in
|
|
each hand there is a clear winner.
|
|
|
|
How many hands does Player 1 win?
|
|
"""
|
|
|
|
# 3 help functions.
|
|
def replace_values_in_string(text: str, args_dict: dict) -> str:
|
|
for k, v in args_dict.items():
|
|
text = text.replace(k, str(v))
|
|
return text
|
|
|
|
def n_of_a_kind(hand: list, n: int) -> int:
|
|
return max([x for x in hand if hand.count(x) == n] or [0])
|
|
|
|
def to_numerical(hand: list) -> list:
|
|
return sorted([int(x[:-1]) for x in hand], reverse=True)
|
|
|
|
|
|
# 10 Ranks functions.
|
|
def high_card(str_hand: list) -> list:
|
|
return to_numerical(str_hand)
|
|
|
|
def one_pair(hand: list) -> int:
|
|
return n_of_a_kind(hand, 2)
|
|
|
|
def two_pair(hand: list) -> int:
|
|
pairs = set([x for x in hand if hand.count(x) == 2])
|
|
return 0 if len(pairs) < 2 else max(pairs)
|
|
|
|
def three_of_a_kind(hand: list) -> int:
|
|
return n_of_a_kind(hand, 3)
|
|
|
|
def straight(hand: list) -> int:
|
|
return 0 if not list(range(hand[0], hand[-1]-1, -1)) == hand else max(hand)
|
|
|
|
def flush(str_hand: list) -> bool:
|
|
return len(set([x[-1] for x in str_hand])) == 1
|
|
|
|
def full_house(hand: list) -> int:
|
|
return three_of_a_kind(hand) if one_pair(hand) and three_of_a_kind(hand) else 0
|
|
|
|
def four_of_a_kind(hand: list) -> int:
|
|
return n_of_a_kind(hand, 4)
|
|
|
|
def straight_flush(str_hand: list) -> int:
|
|
straight_result = straight(to_numerical(str_hand))
|
|
return straight_result if straight_result and flush(str_hand) else 0
|
|
|
|
def royal_flush(str_hand: list) -> bool:
|
|
return flush(str_hand) and list(range(14, 9, -1)) == to_numerical(str_hand)
|
|
|
|
|
|
replace_map = {"T": 10, "J": 11, "Q": 12, "K": 13, "A": 14}
|
|
score = [0, 0]
|
|
|
|
file = Path("/datos/Scripts/Gitea/Project_Euler/src/files/Problem54.txt")
|
|
for line in open(file, "r").read().splitlines():
|
|
line = replace_values_in_string(line, replace_map).split()
|
|
hands = line[:5], line[5:]
|
|
for rank in (royal_flush, straight_flush, four_of_a_kind, full_house, flush,
|
|
straight, three_of_a_kind, two_pair, one_pair, high_card):
|
|
should_convert_hand = "str" not in rank.__code__.co_varnames[0] # Checks parameter name.
|
|
result = [rank(to_numerical(hand) if should_convert_hand else hand) for hand in hands]
|
|
if result[0] != result[1]:
|
|
score[0 if result[0] > result[1] else 1] += 1
|
|
break
|
|
|
|
return score[0]
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
print(f"Result for Problem 54: {compute()}") |