diff --git a/src/Python/Problem054.py b/src/Python/Problem054.py new file mode 100644 index 0000000..1a1e6f3 --- /dev/null +++ b/src/Python/Problem054.py @@ -0,0 +1,134 @@ +#!/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 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] + for line in open("../files/Problem54.txt", "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()}") \ No newline at end of file