반응형
이번 문제는 어렵다는 생각은 들지 않았지만, 상당히 귀찮은 문제이긴 합니다.
프로젝트 오일러 사이트에서의 난이도는 10% 문제입니다.
고포류 게임을 만들어본 적은 없지만, 포커의 룰에 따라서 누가 이겼는지를 판정하는 것은 포커 게임에서 가장 중요한 부분입니다. 그 외의 것이야 인터페이스이니까요.
이번 문제는 상당히 깁니다.
최종적인 이야기는 결국 주어진 카드를 보고서 첫번째 사용자가 몇번 이겼는 가를 판정하는 것입니다.
사실, 이런 판정시스템을 만드는 것이 단순히 노가다만은 아닙니다. 얼마나 더 효율적으로 판단할 수 있게 하는 것이 프로그램을 작성하는 사람에게는 고민이겠죠. 고포류 게임에서 노가다로 프로그램 짠다고 해서, 효율적 프로그램에 비해서 훨씬 더 느리다던지 하는 것은 아닙니다. 프로그램 코드 사이즈가 좀 줄어들고, 속도가 좀 빨라지겠지만, 그래픽 게임에서 그정도의 성능 감소를 알아챌 수는 절대 없습니다. 말 그대로 0.00001 초의 차이고, 그래픽 리소스에 비해서 턱없이 작은 사이즈의 코드량입니다.
어떻게 보면, 보다 효율적인 로직을 구성하고자 하는 것은 프로그래머의 아집일지도 모르겠네요.
일단, 저는 포커에서 어떤 카드를 구성했는지 종류를 판단하고, 그 종류에서 점수를 매겼습니다. 종류가 더 위라면, 당연히 승리이고, 같다면, 점수가 높은쪽이 승리하게 했습니다. 원래 노가다 프로그램을 한다면 더 길어지겠지만, 나름대로 짧게 짜 보았습니다.
#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; }
이 프로그램을 돌렸을 때의 결과 중 일부입니다.
728x90
'Programming > Project Euler' 카테고리의 다른 글
56. 프로젝트 오일러 #56 : 제곱수의 자릿수 합 (0) | 2016.06.13 |
---|---|
프로젝트 오일러 #55 라이크렐 수 (0) | 2016.06.10 |
프로젝트 오일러 #53 : 조합 선택 (0) | 2016.06.09 |
52. 프로젝트 오일러 #52 : 순열 곱 (0) | 2016.06.09 |
51. 프로젝트 오일러 #51 : 소수 자릿수 대치 (0) | 2016.06.08 |
댓글