본문 바로가기
Programming/Project Euler

54. 프로젝트 오일러 #54 : 포커 승리 판정

by 작은별하나 2016. 6. 10.
반응형

이번 문제는 어렵다는 생각은 들지 않았지만, 상당히 귀찮은 문제이긴 합니다.

프로젝트 오일러 사이트에서의 난이도는 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

댓글