본문 바로가기
Programming/Project Euler

[C/C++] 프로젝트 오일러 #54 : 포커 승리 판정

by 작은별하나(A Little Star) 2016. 6. 10.

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

프로젝트 오일러 사이트에서의 난이도는 10% 문제입니다.

 

고포류 게임을 만들어본 적은 없지만, 포커의 룰에 따라서 누가 이겼는지를 판정하는 것은 포커 게임에서 가장 중요한 부분입니다.  그 외의 것이야 인터페이스이니까요.

 

 

이번 문제는 상당히 깁니다.

최종적인 이야기는 결국 주어진 카드를 보고서 첫번째 사용자가 몇번 이겼는 가를 판정하는 것입니다.


사실, 이런 판정시스템을 만드는 것이 단순히 노가다만은 아닙니다.  얼마나 더 효율적으로 판단할 수 있게 하는 것이 프로그램을 작성하는 사람에게는 고민이겠죠.  고포류 게임에서 노가다로 프로그램 짠다고 해서, 효율적 프로그램에 비해서 훨씬 더 느리다던지 하는 것은 아닙니다.  프로그램 코드 사이즈가 좀 줄어들고, 속도가 좀 빨라지겠지만, 그래픽 게임에서 그정도의 성능 감소를 알아챌 수는 절대 없습니다.  말 그대로 0.00001 초의 차이고, 그래픽 리소스에 비해서 턱없이 작은 사이즈의 코드량입니다.

 

어떻게 보면, 보다 효율적인 로직을 구성하고자 하는 것은 프로그래머의 아집일지도 모르겠네요.

 

poker game

 

일단, 저는 포커에서 어떤 카드를 구성했는지 종류를 판단하고, 그 종류에서 점수를 매겼습니다.  종류가 더 위라면, 당연히 승리이고, 같다면, 점수가 높은쪽이 승리하게 했습니다.  원래 노가다 프로그램을 한다면 더 길어지겠지만, 나름대로 짧게 짜 보았습니다.

//------------------------------------------------
//    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;
}

 

 

이 프로그램을 돌렸을 때의 결과 중 일부입니다.

 

반응형

댓글