<reponame>CaptainSora/Python-Project-Euler
from collections import Counter

CARDORDER = ['A', 'K', 'Q', 'J', 'T', '9', '8', '7', '6', '5', '4', '3', '2']
HANDORDER = ['SF', '4K', 'FH', 'FL', 'ST', '3K', '2P', '1P', 'HC']


def high_card(hand):
    """
    Returns the character for the highest card in the hand.
    """
    for a in CARDORDER:
        if a in [x[0] for x in hand]:
            return a


def valuesearch(hand):
    """
    Returns the string code for the best card set if it exists in the hand.
    """
    diff = [x[0] for x in hand]
    values = list(dict.fromkeys(diff))
    for a in values:
        # Leaves only duplicates
        diff.remove(a)
    # sorted in descending order
    diff.sort(key=CARDORDER.index)
    if len(diff) == 0:
        return "HC" + high_card(hand)
    elif len(diff) == 1:
        return "1P" + diff[0]
    elif len(diff) == 2:
        # Two pair or Three of a kind
        if diff[0] == diff[1]:
            return "3K" + diff[0]
        else:
            return "2P" + diff[0] + diff[1]
    elif len(diff) == 3:
        # Full House or Four of a Kind
        if diff[0] == diff[1] == diff[2]:
            return "4K" + diff[0]
        else:
            return "FH" + Counter(diff).most_common(1)[0][0]


def flushsearch(hand):
    """
    Returns true if a flush exists in the hand.
    """
    return len(list(dict.fromkeys(x[1] for x in hand))) == 1


def straightsearch(hand):
    """
    Returns the string code for a straight if it exists in the hand.
    """
    values = [x[0] for x in hand]
    values.sort(key=CARDORDER.index)
    startindex = CARDORDER.index(values[0])
    if startindex > 8: # highest card < 6
        return ""
    for a in range(1, 5):
        if values[a] != CARDORDER[startindex + a]:
            return ""
    return "ST" + values[0]


def besthand(hand):
    """
    Returns the string code for the best possible 5-card set in the hand.
    """
    flush = flushsearch(hand)
    straight = straightsearch(hand)
    value = valuesearch(hand)
    if flush and straight != "":
        return "SF" + straight[2]
    elif value[:2] == "4K" or value[:2] == "FH":
        return value
    elif flush:
        return "FL2"
    elif straight != "":
        return straight
    else:
        return value


def winner(hand1, hand2):
    """
    Returns True if hand1 beats hand2.
    """
    best = [besthand(hand1), besthand(hand2)]
    handtype = [HANDORDER.index(x[:2]) for x in best]
    value = [CARDORDER.index(x[2]) for x in best]
    if handtype[0] != handtype[1]:
        return handtype[0] < handtype[1]
    elif value[0] != value[1]:
        return value[0] < value[1]
    else:
        diff = sorted(set(x[0] for x in hand1) ^ set(x[0] for x in hand2))
        return diff[0] in [x[0] for x in hand1]


def poker_hands():
    """
    Returns the number of hands player 1 wins.
    """
    with open('p054_poker.txt', 'r') as f:
        rawcards = f.read().split()
    p1 = []
    p2 = []
    for a in range(int(len(rawcards)/10)):
        p1.append(rawcards[10*a:10*a+5])
        p2.append(rawcards[10*a+5:10*a+10])

    return sum(winner(p1[a], p2[a]) for a in range(len(p1)))


def solve(vol=0):
    return poker_hands()
