파이썬으로 수학문제 풀기- 프로젝트 오일러(project euler, 22번부터)

프로젝트 오일러 54번 - 포커게임

https://projecteuler.net/problem=54

포커게임 룰은 모르시는분은 별로 없을거라 생각되네요.

  • 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.

위와 같은 룰을 가지고, 아래의 카드 패를 분석해서, 한 사람이 몇번을 이겼는지를 세는 문제입니다.

8C TS KC 9H 4S 7D 2S 5D 3S AC
5C AD 5D AC 9C 7C 5H 8D TD KS
3H 7H 6S KC JS QH TD JC 2D 8S
TH 8H 5C QS TC 9H 4D JC KS JS
7C 5H KC QH JD AS KH 4C AD 4S
5H KS 9C 7D 9H 8D 3S 5D 5C AH
6H 4H 5C 3H 2H 3S QH 5S 6S AS
TD 8C 4H 7C TC KC 4C 3H 7S KS
7C 9C 6D KD 3H 4C QS QC AC KH

 카드는 각 줄이 한 게임이고, 왼쪽 5장이 player 1, 오른쪽 5장이 player 2 입니다. 게임수는 총 1000 줄입니다.

 

카드 카운드

여러가지로 풀수 있겠지만, 가장 간단하게 풀수있는 방법은, 카드를 카운트 하는겁니다.

8CTSKC9H4S 7D2S5D3SAC  

카드를 5장씩 묶어서 문자열로 만들고, '23456789TJQKACSHD' 순서로 카운트를 해서  아래처럼 만들어 줍니다.

000100011100102210 011010100000011202

제일 앞에는 의미없는 0 이 하나더 추가되어 있고 그다음 13자리는 23456789TJQKA 의 카드넘버를 의미하고, 마지막 네자리는 CSHD(클로버,스페이드,하트,다이아몬드)의 카드모양을 의미합니다. 제일앞의 0은 인덱스 0을 방지하기 위해서입니다.

데이터 형식은 여러가지로 쓸수 있겠지만, 이런식으로 바꿔주면 if문으로 조건을 걸어주기가 편해집니다. 예를들어 23456 스트레이트는 아래와 같고,

011111000000001040

 4 one-pair 는 아래와 같습니다.

001210010000000113

 

조건문 만들기
if '1' in pair:        
if pair.count('2')==1: 
if pair.count('2')==2: 
if '3' in pair:        
if '11111' in pair: 
if '5' in suit:        
if rank[1] != 0 and rank[3] != 0 :     
if '4' in pair:          
if rank[4] != 0 and rank[5] != 0 : 

이런식으로 문자열을 카운트하면, 그다음부터는 조건문을 간단하게 만들어줄수 있습니다.

 

랭킹 판별
[12, 0, 0, 0, 0, 0, 0, 0, 0] [13, 0, 0, 0, 0, 0, 0, 0, 0] 
[8, 0, 13, 0, 0, 0, 0, 0, 0] [12, 0, 0, 0, 0, 0, 0, 0, 0] 
[12, 0, 0, 0, 0, 0, 0, 0, 0] [11, 0, 0, 0, 0, 0, 0, 0, 0] 

랭킹은 별도의 9자리 리스트를 만들어서 왼족부터 high card, one-pair, two-pair, 3-card, 스트레이트,,,, 의 카드를 표시해줍니다. 들어갈 숫자는, 각 케이스의 가장 큰 카드숫자입니다.

이렇게 만들면, 이 리스트를 오른쪽에서부터 차례대로 비교해주면, 먼저 큰숫자가 나오는쪽이 이기게 됩니다.

 

최종코드
with open('p054_poker.txt') as data:
    games = [''.join(i.split()) for i in data.readlines()]

def winner(r1,r2):
    for i in range(8,-1,-1):
        if r1[i]>r2[i]:
            return 'p1'
        elif r1[i]<r2[i]:
            return 'p2'
    return 'tie'

def grader(count):
    pair = count[:14]  # fixed here
    suit = count[14:18]  # fixed here
    rank=[0]*9
    if '1' in pair:        rank[0] = pair.rindex('1')
    if pair.count('2')==1: rank[1] = pair.index('2')
    if pair.count('2')==2: rank[2] = pair.rindex('2')
    if '3' in pair:        rank[3] = pair.index('3')
    if '11111' in pair:    rank[4] = rank[0]
    if '5' in suit:        rank[5] = rank[0]   
    if rank[1] != 0 and rank[3] != 0 : rank[6] = rank[3]    
    if '4' in pair:                    rank[7] = pair.index('4')
    if rank[4] != 0 and rank[5] != 0 : rank[8] = rank[4]    
    return rank

def counter(g):
    c='0'  # fixed here
    for i in '23456789TJQKACSHD':
        c+=str(g.count(i))
    return c

p1count=0
for g in games:
    g1=grader(counter(g[:10]))
    g2=grader(counter(g[10:20]))
    if winner(g1,g2)=='p1':
        p1count+=1
print(p1count)

 

댓글

댓글 본문
작성자
비밀번호
graphittie 자세히 보기