포커라는 카드게임은 다섯 장으로 된 패의 높고 낮음에 따라 승부를 냅니다. (포커 규칙을 이미 아는 분이라면 규칙 설명 부분은 건너뛰셔도 좋습니다)
카드 한 장은 아래와 같은 순서대로 값이 높아집니다.
2, 3, 4, 5, 6, 7, 8, 9, 10, J, Q, K, A
다섯 장으로 이루어진 패의 계급(세칭 “족보”)은, 낮은 것부터 높은 순서로 아래와 같습니다.
-
High Card : 가장 높은 카드의 값으로 비교.
-
One Pair : 한 쌍이 같은 카드.
-
Two Pairs : 서로 다른 두 쌍이 같은 카드.
-
Three of a Kind : 세 장이 같은 카드.
-
Straight : 모든 카드가 연속된 숫자.
-
Flush : 모든 카드의 무늬가 같음.
-
Full House : 세 장이 같고, 또 한 쌍이 같음 (Three of a Kind + One Pair).
-
Four of a Kind : 네 장이 같은 카드.
-
Straight Flush : 모든 카드가 연속된 숫자이면서 무늬도 같음.
-
Royal Flush : 10, J, Q, K, A가 무늬도 같음.
두 사람의 패가 같은 종류의 계급이라면, 계급을 구성하는 카드 중 높은 쪽을 쥔 사람이 이깁니다. 예를 들면 8 원페어는 5 원페어를 이깁니다.
계급을 이루는 카드 숫자까지 같으면 (예: 둘 다 Q 원페어), 다른 카드를 높은 순서대로 비교해서 승부를 정합니다.
텍스트파일 poker.txt 에는 두 선수가 벌인 1,000회의 승부가 저장되어 있습니다. (우클릭해서 다운로드 받으세요)
한 줄에는 10장의 카드가 공백으로 분리되어 들어있는데, 앞의 다섯 장은 1번 선수 것이고 뒤의 다섯 장은 2번 선수의 패입니다. 잘못되거나 중복된 데이터는 없으며, 무승부도 없습니다.
카드 숫자는 2, 3, … , 9, T, J, Q, K, A 로 (숫자 10은 T로 표시),
무늬는 C (Club – ♣), D (Diamond – ♦), H (Heart – ♥), S (Spade – ♠) 로 표시되어 있습니다.
예를 들면 3C 3D 3S 9S 9D 의 경우 3 풀하우스가 됩니다.
이 데이터를 분석하고, 1번 선수가 이긴 횟수를 구하세요.
참 문제가 길다.
포커 규칙에 따라서 핸드에 있는 패의 점수를 부여하고, 두 사람의 핸드를 비교해서 이긴사람을 구하는 방식으로 문제를 해결 할 수 있을 것이다.
물론 점수를 부여하는 함수를 만드는 부분이 매우 귀찮은(…) 부분이 될 것 같았다.
첫 프로젝트 오일러 시작에서 설명했던 것과 같이, 나는 함수 구현보다 문제를 푼다는 것에 집중하기로 했으므로, 모듈을 찾아봤다.
그 결과 아주 적절한 Games::Cards::Poker 모듈을 발견하여 사용하기로 했다.
내가 원하는 함수가 모두 구현되어 있었으므로, 아주 간단했다.
추가로, 이전까지는 문제에서 주어진 데이터를 코드에 직접 삽입하여 문제풀이를 하였으나, 이번 파일부터 그 크기가 감당할 수 없이 커져버렸다.
따라서 외부 파일에서 데이터를 불러와 사용하기로 하였는데, 나는 명령행 인자로 파일 경로를 넘겨주는 방식으로 구현했다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
#!/usr/bin/env perl use 5.010; use strict; use warnings; use Games::Cards::Poker; #명령행 인자로 파일 이름 넘겨줄 것. my $c = 0; while (<>) { my @a = split(/ /, $_); $c++ if (ScoreHand(@a[0..4]) < ScoreHand(@a[5..9])); } say $c; |