🔒 문제
https://projecteuler.net/problem=54
원문은 영어로 되어있지만 구글 번역기의 도움을 받았다.
[poker hands]
카드 게임 포커에서 핸드는 5장의 카드로 구성되며 다음과 같은 방식으로 가장 낮은 것부터 가장 높은 것까지 순위가 매겨집니다.
- High Card : 가장 가치가 높은 카드.
- One Pair : 같은 값의 두 장의 카드.
- Two Pairs : 두 개의 다른 쌍.
- Three of a Kind : 같은 값의 카드 3장.
- Straight : 모든 카드는 연속된 값입니다.
- Flush : 같은 슈트의 모든 카드.
- Full House : 세 종류와 한 쌍.
- Four of Kind : 같은 값의 카드 4장.
- Straight Flush : 모든 카드는 동일한 슈트의 연속 값입니다.
- Royal Flush : 텐, 잭, 퀸, 킹, 에이스, 같은 슈트.
카드의 가치는
2, 3, 4, 5, 6, 7, 8, 9, 10, 잭, 퀸, 킹, 에이스 순입니다.
두 명의 플레이어가 동일한 랭킹 핸드를 가지고 있으면 가장 높은 값으로 구성된 랭크가 승리합니다. 예를 들어, 8 쌍이 5 쌍을 이깁니다(아래 예 1 참조). 그러나 예를 들어 두 등급이 동률인 경우 두 플레이어 모두 한 쌍의 퀸을 가지고 있는 경우 각 핸드에서 가장 높은 카드가 비교됩니다(아래 예 4 참조). 가장 높은 카드가 동점인 경우 다음으로 높은 카드가 비교되는 식입니다.
두 명의 플레이어에게 다음 5가지 핸드를 처리하는 것을 고려하십시오.
Hand | Player 1 | Player 2 | Winner |
1 | 5H 5C 6S 7S KD Pair of Fives
|
2C 3S 8S 8D TD Pair of Eights
|
Player 2 |
2 | 5D 8C 9S JS AC Highest card Ace
|
2C 5C 7D 8S QH Highest card Queen
|
Player 1 |
3 | 2D 9C AS AH AC Three Aces
|
3D 6D 7D TD QD Flush with Diamonds
|
Player 2 |
4 | 4D 6S 9H QH QC Pair of Queens
Highest card Nine |
3D 6D 7H QD QS Pair of Queens
Highest card Seven |
Player 1 |
5 | 2H 2D 4C 4D 4S Full House
With Three Fours |
3C 3D 3S 9S 9D Full House
with Three Threes |
Player 1 |
poker.txt 파일 에는 2명의 플레이어에게 1,000개의 무작위 핸드가 포함되어 있습니다. 파일의 각 줄에는 10장의 카드가 있습니다(공백 하나로 구분). 처음 5장은 참가자 1의 카드이고 마지막 5장은 참가자 2의 카드입니다. 모든 패가 유효하고(유효하지 않은 문자나 반복되는 카드가 없음), 각 플레이어의 패가 특정한 순서가 없으며, 각 패에 확실한 승자가 있다고 가정할 수 있습니다.
플레이어 1은 몇 핸드를 이기나요?
🔓 풀이
🔑 문제 해결 / 코드
"""
개요 : 5장으로 하는 핸드포커게임 만들기
input | poker_file: file.txt (1000게임)
output | result: int (player1의 승리 횟수)
10장의 카드가 주어졌을 때 앞 5장은 player1, 뒤 5장은 player2의 카드가 되어 비교하여 승자를 정한다.
"""
"""
## 비고 ##
1. 10은 T이기도 함(주어진 텍스트 파일 마지막에 J대신 10이 들어있음)
2. 핸드, 패 비교 동점인경우 무승부, 승리 카운트 X
"""
# 핸드 랭크 딕셔너리
rank_dict = {"Royal flush": 10, "Straight flush": 9, "Four of a kind": 8, "Full house": 7, "Flush": 6,
"Straight": 5, "Three of a kind": 4, "Two pair": 3, "Pair": 2, "High card": 1}
#################################
# 핸드 체크 함수 시작 #
#################################
# 원페어 체크
def check_pair(hand_rankings):
pair_count = 0
hand_rankings[0] = 0
for i in hand_rankings:
if i == 2:
pair_count += 1
if pair_count == 1:
return True
else:
return False
# 투페어 체크
def check_two_pair(hand_rankings):
pair_count = 0
for i in hand_rankings:
if i == 2:
pair_count += 1
if pair_count == 2:
return True
else:
return False
# 트리플 체크
def check_three_of_a_kind(hand_rankings):
for i in hand_rankings:
if i == 3:
return True
return False
# 스트레이트 체크
def check_straight(hand_rankings):
straight_count = 0
# 1이 연속으로 5번 나오면 스트레이트 // straight_count = 5
for i in hand_rankings:
if straight_count == 5:
return True
if i == 1:
straight_count += 1
else:
straight_count = 0
if straight_count == 5:
return True
return False
# 플러시 체크
def check_flush(p_suit):
if len(set(p_suit)) == 1:
return True
else:
return False
# 풀하우스 체크
def check_full_house(hand_rankings):
if check_three_of_a_kind(hand_rankings) and check_pair(hand_rankings):
return True
else:
return False
# 포카드 체크
def check_four_of_a_kind(hand_rankings):
for p in hand_rankings:
if p == 4:
return True
return False
# 스트레이트 플러시 체크
def check_straight_flush(p_suit ,hand_rankings):
if check_straight(hand_rankings) and check_flush(p_suit):
return True
else:
return False
# 로얄 플러시 체크
def check_royal_flush(p_num, p_suit):
if p_num == [10, 11, 12, 13, 14] and check_flush(p_suit):
return True
else:
return False
################################
# 핸드 체크 함수 끝 #
################################
# 손패 순위 정하기
def rank(p_num, p_suit):
hand_rankings = [0]*14
rank = "High card"
for num in p_num:
hand_rankings[num-1] += 1
if num == 14: # 카드가 Ace인 경우 0번째 인덱스에도 추가
hand_rankings[0] += 1
# Royal flush
if check_royal_flush(p_num, p_suit):
rank = "Royal flush"
# Straight flush
elif check_straight_flush(p_suit, hand_rankings):
rank = "Straight flush"
# Four of a kind
elif check_four_of_a_kind(hand_rankings):
rank = "Four of a kind"
# Full house
elif check_full_house(hand_rankings):
rank = "Full house"
# Flush
elif check_flush(p_suit):
rank = "Flush"
# Straight
elif check_straight(hand_rankings):
rank = "Straight"
# Three of a kind
elif check_three_of_a_kind(hand_rankings):
rank = "Three of a kind"
# Two pair
elif check_two_pair(hand_rankings):
rank = "Two pair"
# Pair
elif check_pair(hand_rankings):
rank = "Pair"
return rank, rank_dict[rank], hand_rankings
# 플레이어 카드 숫자와 문양 구분하기
def player_num_suit_split(player):
p_num_list = []
p_suit_list = []
card_dict = {"T": 10, "J": 11, "Q": 12, "K": 13, "A": 14}
for p in player:
# 카드 숫자와 문양 구분하기
p_num= p[:-1]
p_suit = p[-1]
try: # 영문인 경우
p_num_list.append(card_dict[p_num])
except KeyError: # 숫자인 경우
p_num_list.append(int(p_num))
p_suit_list.append(p_suit)
# 카드 숫자 오름차순 정렬
p_num_list.sort()
return p_num_list, p_suit_list
#############################
# 핸드가 같을경우 비교 함수 #
#############################
# hand_rankings revers index 비교
def compare_hand_rankings_revers_index(p1_hand_rankings, p2_hand_rankings):
p1_hand_rankings.reverse()
p2_hand_rankings.reverse()
for p1, p2 in zip(p1_hand_rankings, p2_hand_rankings):
if p1 > p2:
return True
elif p1 < p2:
break
# hand rankings number index 비교
def compare_hand_rankings_number_index(p1_hand_rankings, p2_hand_rankings, number):
# hand rankings 에서 ace 1번위치 지워주기
p1_hand_rankings[0] = 0
p2_hand_rankings[0] = 0
# hand rankings 3 index 비교
if p1_hand_rankings.index(number) > p2_hand_rankings.index(number):
return True
# 게임 함수
def play_game(player1, player2):
p1_num, p1_suit = player_num_suit_split(player1)
p2_num, p2_suit = player_num_suit_split(player2)
p1_hand, p1_rank, p1_hand_rankings = rank(p1_num, p1_suit)
p2_hand, p2_rank, p2_hand_rankings = rank(p2_num, p2_suit)
# print(f"p1: {p1_hand} | p2: {p2_hand}") TODO
if p1_rank > p2_rank:
return True
# 핸드가 같을 경우
elif p1_rank == p2_rank:
if p1_hand and p2_hand == "High card":
# hand_rankings revers index 비교
if compare_hand_rankings_revers_index(p1_hand_rankings, p2_hand_rankings):
return True
elif p1_hand and p2_hand == "Pair":
if p1_hand_rankings.index(2) > p2_hand_rankings.index(2):
return True
elif p1_hand_rankings.index(2) == p2_hand_rankings.index(2):
# hand_rankings revers index 비교
if compare_hand_rankings_revers_index(p1_hand_rankings, p2_hand_rankings):
return True
elif p1_hand and p2_hand == "Two pair":
p1_index = [i for i, y in enumerate(p1_hand_rankings) if y == 2]
p2_index = [i for i, y in enumerate(p2_hand_rankings) if y == 2]
# print(p1_index, p2_index) TODO
if p1_index[1] > p2_index[1]:
return True
elif p1_index[1] == p2_index[1]:
if p1_index[0] > p2_index[0]:
return True
elif p1_index[0] == p2_index[0]:
# hand rankings 에서 ace 1번위치 지워주기
p1_hand_rankings[0] = 0
p2_hand_rankings[0] = 0
if p1_hand_rankings.index(1) > p2_hand_rankings.index(1):
return True
elif p1_hand and p2_hand == "Three of a kind":
# hand rankings number index 비교
if compare_hand_rankings_number_index(p1_hand_rankings, p2_hand_rankings, 3):
return True
elif p1_hand and p2_hand == "Straight":
# hand_rankings revers index 비교
if compare_hand_rankings_revers_index(p1_hand_rankings, p2_hand_rankings):
return True
elif p1_hand and p2_hand == "Flush":
# hand_rankings revers index 비교
if compare_hand_rankings_revers_index(p1_hand_rankings, p2_hand_rankings):
return True
elif p1_hand and p2_hand == "Full house":
# hand rankings number index 비교
if compare_hand_rankings_number_index(p1_hand_rankings, p2_hand_rankings, 3):
return True
elif p1_hand and p2_hand == "Four of a kind":
# hand rankings number index 비교
if compare_hand_rankings_number_index(p1_hand_rankings, p2_hand_rankings, 4):
return True
elif p1_hand and p2_hand == "Straight flush":
# hand_rankings revers index 비교
if compare_hand_rankings_revers_index(p1_hand_rankings, p2_hand_rankings):
return True
# 둘다 로얄 플러쉬 나오는 경우는 무승부
elif p1_hand and p2_hand == "Royal flush":
pass
return False
# 게임 시작하기
def start_game(poker_txt_file):
# Poker.txt 파일 열기
poker_file = open(poker_txt_file, "r")
# 모든 line 가져오기
lines = poker_file.readlines()
# type(line[0]) = str
p1_number_of_win = 0
for line in lines:
# 줄바꿈 제거 (\n)
line = line.strip()
# player 카드분배
cards = line.split(" ")
player1 = cards[:5]
player2 = cards[5:]
# print(f"p1_hand: {player1} | p2_hand: {player2}") TODO
if play_game(player1, player2):
p1_number_of_win += 1
# Poker.txt 파일 닫기
poker_file.close()
return p1_number_of_win
print(start_game("Poker.txt"))
💉 피드백
분명 이렇게 길게 쓸 코드가 아닐 텐데 쓰다 보니 어느새 300줄이 훌쩍 넘어버렸다. (함수가 몇 개야,,,)
간단한 포커게임이지만 구현하는데 고민에 또 고민을,, 좋은 코더의 길은 멀고도 험하구나 ㅠ
속도, 성능에 신경 쓰기보단 최대한 주어진 조건을 충족하는 함수를 만들고자 노력했는데 정확도가 얼마나 될지는 모르겠다.
프로그래머스처럼 제출해서 채점이 되면 좋을 텐데 마땅한 답안이 없어서 찜찜하지만, 그래도 완성은 해서 기분은 좋다 😁
'알고리즘' 카테고리의 다른 글
[프로그래머스] 3진법 뒤집기_Python level1 (0) | 2022.05.19 |
---|---|
[기술 테스트 과제] 핑퐁게임_python (0) | 2022.05.09 |
[프로그래머스] 실패율_python (0) | 2022.05.02 |
[프로그래머스] 약수의 개수와 덧셈_Python (0) | 2022.05.02 |
[프로그래머스] 모의고사_Python_완전탐색 (0) | 2022.05.01 |