이번 문제는 어렵다는 생각은 들지 않았지만, 상당히 귀찮은 문제이긴 합니다.
프로젝트 오일러 사이트에서의 난이도는 10% 문제입니다.
고포류 게임을 만들어본 적은 없지만, 포커의 룰에 따라서 누가 이겼는지를 판정하는 것은 포커 게임에서 가장 중요한 부분입니다. 그 외의 것이야 인터페이스이니까요.

이번 문제는 상당히 깁니다.
최종적인 이야기는 결국 주어진 카드를 보고서 첫번째 사용자가 몇번 이겼는 가를 판정하는 것입니다.
사실, 이런 판정시스템을 만드는 것이 단순히 노가다만은 아닙니다. 얼마나 더 효율적으로 판단할 수 있게 하는 것이 프로그램을 작성하는 사람에게는 고민이겠죠. 고포류 게임에서 노가다로 프로그램 짠다고 해서, 효율적 프로그램에 비해서 훨씬 더 느리다던지 하는 것은 아닙니다. 프로그램 코드 사이즈가 좀 줄어들고, 속도가 좀 빨라지겠지만, 그래픽 게임에서 그정도의 성능 감소를 알아챌 수는 절대 없습니다. 말 그대로 0.00001 초의 차이고, 그래픽 리소스에 비해서 턱없이 작은 사이즈의 코드량입니다.
어떻게 보면, 보다 효율적인 로직을 구성하고자 하는 것은 프로그래머의 아집일지도 모르겠네요.

일단, 저는 포커에서 어떤 카드를 구성했는지 종류를 판단하고, 그 종류에서 점수를 매겼습니다. 종류가 더 위라면, 당연히 승리이고, 같다면, 점수가 높은쪽이 승리하게 했습니다. 원래 노가다 프로그램을 한다면 더 길어지겠지만, 나름대로 짧게 짜 보았습니다.
//------------------------------------------------
// Project Euler #54 - Poker Hands
// - by Aubrey Choi
// - created at 2015-03-31
//------------------------------------------------
#include <stdio.h>
#include <string.h>
#define FN "p054_poker.txt"
struct Cards
{
int numbers;
int straight;
int suits[4];
int flush;
int pairs[14];
int paircount;
int triple;
int pairbit;
int kind;
};
int GetScore(Cards &c);
int main()
{
int win = 0;
int number[128];
int suit[128];
const char *res[10] = { "", "HIGH", "ONEP", "TWOP", "TRIP", "STRA", "FLUS", "FULL", "FOUR", "STFL" };
for( int i = 2 ; i < 10 ; i++ ) number[i+'0'] = i-1;
number['T'] = 9; number['J'] = 10; number['Q'] = 11; number['K'] = 12;
number['A'] = 13;
suit['S'] = 0; suit['D'] = 1; suit['H'] = 2; suit['C'] = 3;
FILE *fi = fopen(FN, "r");
char line[128];
while( fgets(line, 128, fi) )
{
Cards cards[2];
memset(cards, 0, sizeof(cards));
char *tok = strtok(line, " \n\r");
for( int i = 0 ; i < 10 ; i++, tok = strtok(0, " \n\r") )
{
printf("%s ", tok);
int n = number[*tok], s = suit[*(tok+1)];
cards[i/5].numbers |= 1<<n; if( n == 13 ) cards[i/5].numbers |= 1;
cards[i/5].suits[s]++;
cards[i/5].pairs[n]++;
}
int score1 = GetScore(cards[0]);
int score2 = GetScore(cards[1]);
printf("%s, %s, %d %d\n", res[cards[0].kind], res[cards[1].kind], score1, score2);
if( cards[0].kind > cards[1].kind ) win++;
else if( cards[0].kind == cards[1].kind && score1 > score2 ) win++;
}
fclose(fi);
printf("ans = %d\n", win);
}
int GetScore(Cards &c)
{
for( int i = 1 ; i <= 13 ; i++ ) if( ((c.numbers>>i) & 0x1f) == 0x1f ) c.straight = i+4;
for( int i = 0 ; i < 4 ; i++ ) if( c.suits[i] == 5 ) c.flush = 1;
if( c.straight && c.flush ) { c.kind = 9; return c.straight; }
for( int i = 1 ; i <= 13 ; i++ )
{
if( c.pairs[i] == 4 ) { c.kind = 8; return i; }
else if( c.pairs[i] == 3 ) { c.triple = i; c.numbers &= ~(1<<i); }
else if( c.pairs[i] == 2 ) { c.paircount++; c.pairbit |= 1<<i; c.numbers &= ~(1<<i); }
}
if( c.triple && c.pairbit ) { c.kind = 7; return c.triple; }
if( c.flush ) { c.kind = 6; return c.numbers; }
if( c.straight ) { c.kind = 5; return c.straight; }
if( c.triple ) { c.kind = 4; return c.triple; }
if( c.paircount == 2 ) { c.kind = 3; return (c.pairbit<<12) + (c.numbers>>1); }
if( c.paircount == 1 ) { c.kind = 2; return (c.pairbit<<12) + (c.numbers>>1); }
c.kind = 1; return c.numbers;
}
이 프로그램을 돌렸을 때의 결과 중 일부입니다.
'Programming > Project Euler' 카테고리의 다른 글
[C++/Python] 프로젝트 오일러 #56 : 제곱수의 자릿수 합 (0) | 2016.06.13 |
---|---|
[C++/Python] 프로젝트 오일러 #55 라이크렐 수 (0) | 2016.06.10 |
[C/C++] 프로젝트 오일러 #53 : 조합 선택 (0) | 2016.06.09 |
[C/C++] 프로젝트 오일러 #52 : 순열 곱 (0) | 2016.06.09 |
[C/C++] 프로젝트 오일러 #51 : 소수 자릿수 대치 (0) | 2016.06.08 |
댓글