Thursday, June 4, 2015

Project Euler #54 - Poker hands

프로젝트 오일러 54번 - 포커패
첨부된 파일에서 1번이 2번을 이기는 경우는 몇 번?

포커 규칙을 모르는 사람은 설명을 읽다가 포기할 문제다.
포커 규칙을 아는 사람도 귀찮아서 포기하기 딱 좋은 문제다.
왜 이걸 하고 있어야 하나.. 싶은 생각이 들지만 그래도 풀어보기로..
패를 점수로 바꾸는 함수를 정의했다. 점수패 0, 원패어 1, 투패어 2, ... 스트레이트플러시 8.
점수가 똑같으면 가장 높은 숫자로 비교해야 하니까(그리고, 가장 높은 숫자가 똑같으면 두번째 높은 숫자로... 동점이면 세번째 숫자... 또 동점이면 네번째 숫자, 그래도 동점이면 다섯번째 숫자로 비교해야 하니까) 높은 숫자들을 역시 점수로 변환한다.
모든 숫자가 똑같을 때 스페이드가 다이아몬드보다 높다거나 하는 규칙도 있지만 여기 문제 설명에 없으니까 코드로 구현할 때는 생략한다.

dic = {'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}

#str_cards = '9H 4D JC KS JS'
def cardreader(str_cards):
    return [(dic[x[0]],x[1]) for x in str_cards.split(' ')]

#cards = [(9, 'H'), (4, 'D'), (10, 'C'), (12, 'S'), (10, 'S')]

def score(cards):
    '''
    Score - ABBCCDDEEFF
    A: high card, 1-pair, 2-pair, ...
        0 - high
        1 - 1-pair
        2 - 2-pairs
        3 - three of a kind
        4 - straight
        5 - flush
        6 - full house
        7 - four of a kind
        8 - straight flush
    BB: highest number
    CC,DD,EE,FF: highest, if none, 00
    '''
    A=B=C=D=E=F=0
    nums = [x[0] for x in cards]
    shapes = [x[1] for x in cards]
    if len(set(nums)) == 5:
        if max(nums) - min(nums) == 4:
            A = 4
            B = max(nums)
            if len(set(shapes)) == 1:
                A = 8
        elif len(set(shapes)) == 1:
            A = 5
            B, C, D, E, F = sorted(nums,reverse=True)
        else:
            A = 0
            B,C,D,E,F = sorted(nums,reverse=True)
    elif len(set(nums)) == 4:
        A = 1
        for x in nums:
            if nums.count(x) == 2: B = x
        C,D,E = sorted([x for x in nums if x != B],reverse=True)
    elif len(set(nums)) == 3:
        for x in nums:
            if nums.count(x) == 3:
                A = 3
                B = x
                C, D = sorted([x for x in nums if x != B], reverse=True)
        if A != 3:
            A = 2
            for x in nums:
                if nums.count(x) == 1: D = x
            tmp = set(nums) - {D}
            B, C = max(tmp), min(tmp)
    elif len(set(nums)) == 2:
        for x in nums:
            if nums.count(x) == 4:
                A = 7
                B = x
                C = max(set(nums) - {B})
        if A != 7:
            A = 6
            for x in nums:
                if nums.count(x) == 3:
                    B = x
                    C = max(set(nums) - {x})
    return A*10**10 + B*10**8 + C*10**6 + D*10**4 + E*10**2 + F


rs = 0
for line in open('p054_poker.txt').readlines():
    p1, p2 = line[:14], line[-15:-1]
    if score(cardreader(p1)) > score(cardreader(p2)):
        rs += 1

print rs

No comments: