되는대로 살자

[C언어 기출문제&풀이] 포커 패(Poker hands) 본문

2009~2014/C/C++

[C언어 기출문제&풀이] 포커 패(Poker hands)

malu 2011. 5. 15. 20:33

포커용 카드느 52개의 카드로 이루어진다. 각 카드는 클럽, 다이아몬드, 하트, 스페이드(입력 데이터에서는 각각 C,D,H,S로 표기) 중 한 가지 무늬를 가진다. 또한 각 카드는 2에서 10까지, 그리고 잭, 퀸, 킹, 또는 에시스(2,3,4,5,6,7,8,9,T,J,Q,K,A로 표기)의 값을 갖는다. 점수를 매길 때 위에 열거한 순서대로 등급이 매겨지며 2가 가장 낮고 에이스가 가장 높다. 무늬는 값에 영향을 기치지 않는다.

포커 패는 다섯 장의 카드로 구성되며 다음과 같은 순서대로 등급이 매겨진다.

하이카드: 아래에 있는 것 가운데 어떤 범주에도 속하지 않는 패는 그 중 가장 높은 카드의 값에 따라 등급이 매겨진다. 가장 높은 카드의 값이 같으면 그 다음 카드, 그 다음 카드도 같으면 그 다음카드, 이런 식으로 등급이 매겨진다.

원 페어: 다섯 장의 카드 가운데 두 장이 같은 경우. 같은 원 페어끼리 맞붙는 경우에는 더 높은 값을 가지는 원 페어 패에 더 높은 등급이 매겨진다. 값까지 같은 경우에는 나머지 카드의 값에 의해 더 높은 패가 결정 된다.
투페어: 두 쌍의 카드가 같은 값을 가지는 경우. 투 페어끼리 맞붙는 경우에는 그 중 더 높은 페어의 값에 의해 더 높은 등급이 매겨진다. 두 쌍의 값이 모두 같으면 남은 카드에 의해 더 높은 패가 결정된다.

쓰리카드: 다섯 장 가운데 세 장이 같은 값을 가지는 경우. 쓰리 카드끼리 맞붙는 경우에는 세 장의 같은 값을 가지는 카드의 ㄱ밧에 의해 더 높은 패가 결정된다.
스트레이트: 다섯 장의카드가 연속적인 값을 가지는 경우. 스트레이트끼리 맞붙을 경우에는 가장 높은 카드에 의해 더 높은 패가 결정된다.
플러시: 다섯 장의 카드의 무늬가 모두 같은 경우. 플러시끼리 맞붙을 경우에는 하이 카드의 규칙에 따라서 더 높은 패가 결정된다.
풀 하우스: 세 장의 카드가 같은 값을 가지고 나머지 두 장의 카드가 같은 값을 가지는 경우. 같은 값을 가지는 세 장의 카드의 우열에 의해 더 높은 패가 결정된다.
포카드:네 장의 카드가 같은 값을 가지는 경우. 포카드끼리 맞붙는 경우에는 네 장의 같은 값을 가지는 카드의 값에 의해 더 높은 패가 결정된다.
스트레이트플러시: 다섯 장의 카드가 무늬가 같으면서 모두 연속적인 값을 가지는 경우. 패에 있는 것 중 가장 높은 카드에 의해 더 높은 패가 결정된다.

몇쌍의 포커 패를 비교해서 어느 ㅉ고이 이겼는지 아니면 무승부인지 알아내자.
입력:입력 파일은 여러 줄로 구성되며 각 줄에는 열 장의 카드를 나타내는 값이 들어간다. 앞에 있는 다섯 장의 카드는 "Black"이라는 참가자의 카드고, 뒤에 있는 다섯 장의 카드는"White"라는 참가자의 카드다.

출력 : 입력된 ㅏㄱㄱ 줄에 대해 다음 중 한 가지가 들어있는 행을 출력한다(첫번째는 Black이 이기는 경우, 두번째는 White가 이기는 경우, 세번째는 둘이 비기는 경우).
Black wins. White wins. Tie.

풀이 :먼저 포커 패의 등급을 비교할 수 있는 족보를 만들고, 주어진 black,white의 카드를 이 족보와 비교해 등급을 매기고, 서로 등급을 비교하여 결과를 출력한다.

소스코드
:#include <stdio.h>

#define CARD_NUM 5
//encode_card에서 숫자는 *10
#define get_value(x) ((x) / 10)
//encode_card에서 종류는 +1,2,3,4
#define get_suit(x) ((x) % 10)

int encode_card(char *card);
long get_hand_value(int hand[5]);

void main(void)
{
 char line[100];
 int hand[2][5]; //hand[Blakc,White][card_num]
 long hand_value[2]; //Black, White
 int i,j,t;
 
 while(gets(line) && *line)
 {
  t=0;
  for(i=0;i<2;i++) //Black, White
  {
   for(j=0;j<5;j++) //숫자
   {
    while(line[t] ==' ') //빈칸은 패스
     t++;
    hand[i][j] = encode_card(line+t); //hand[i][j]에 숫자 입력
    t+=2; //숫자,종류(하트,스페이스....)
   }
   hand_value[i]=get_hand_value(hand[i]); //등급 매기기
  }
  if(hand_value[0] > hand_value[1]) // 검은색 카드의 등급이 더 높을 때
   printf("Black wins.");
  else if(hand_value[0] < hand_value[1])//흰색 카드의 등급이 더 높을 때 
   printf("White wins.");
  else //비겼을 때
   printf("Tie.");
 }
}
int encode_card(char *card)
{
 int result;
 switch(card[0]) // 숫자
 {
 case 'T': result = 100; break;//10
 case 'J': result = 110; break;//Jack
 case 'Q': result = 120; break;//Queen
 case 'K': result = 130; break;//King
 case 'A': result = 140; break;//Ace
 default: result = (card[0] - '0') * 10; //num
 }
 switch(card[1]) // 종류
 {
 case 'H': result+=1; break; //Heart
 case 'D': result+=2; break; //Diamond
 case 'S': result+=3; break; //Space
 case 'C': result+=4; break; //Clober
 }
 return result;
}
//등급 매기는 함수
long get_hand_value(int hand[5])
{
 int i,j,max,temp;
 int value[5],suit[5]; // 값,종류
 long result; // 결과
 //직접 선택법으로 내림차순 정렬
 for(i=0;i<4;i++)
 {
  max=i;
  for(j=i+1;j<5;j++)
   if(hand[j] > hand[max])
    max = j;
   temp = hand[i];
   hand[i] = hand[max];
   hand[max] = temp;
 }
 //정렬을 해 놓으면 등급 계산이 편리하다.
 for(i=0;i<5;i++)
 {
  //값 저장
  value[i] = get_value(hand[i]); // 전처리기 참조
  suit[i] = get_suit(hand[i]); // 전처리기 참조
 }

 //straight flush
 if(value[1]+1==value[0] && suit[1] == suit[0]
  && value[2]+2 == value[0] && suit[2] == suit[0]
  && value[3]+3 == value[0] && suit[3] == suit[0]
  && value[4]+4 == value[0] && suit[4] == suit[0])

  result = (9 << 20)//등급 9개
  +(value[0] << 16);

 //four of a kind (1,4),(2,5)만 검사하면 된다
 else if(value[0] == value[3] || value[1] == value[4])
  result = (8<<20) + (value[1] << 16);

 //full house 2+3,3+2를 검사한다.
 else if(value[0] == value[2] && value[3] == value[4]) //3+2
  result = ( 7<<20) + (value[0] << 16);

 else if(value[0] == value[1] && value[2] == value[4]) //2+3
  result = (7<<20) + (value[2] << 16);

 //flush
 else if(suit[1] == suit[0] && suit[2] == suit[0]
  && suit[3] == suit[0] && suit[4]==suit[0])
  result = (6<<20) + (value[0] << 16) + (value[1] << 12)
  + (value[2] << 8) + (value[3] << 4) + value[4];


 //straight
 else if(value[1]+1 == value[0] && value[2]+2 == value[0]
  && value[3]+3==value[0] && value[4]+4==value[0])
  result=(5<<20) + (value[0]<<16);

 //three of a kind
 else if(value[0] ==value[2] || value[1]==value[3]
  || value[2] == value[4])
  result=(4<<20) + (value[2] << 16);//3번째 카드는 무조건 쓰리카드에 포함

 //two pairs
 else if(value[0]==value[1]&&value[2]==value[3])
  result=(3<<20) + (value[1]<<16) + (value[3] << 12) + (value[4] << 8);
 else if(value[0] == value[1] && value[3]==value[4])
  result = (3<<20) + (value[1] << 16) + (value[3] << 12) + (value[2] << 8);
 else if(value[1] == value[2] && value[3] == value[4])
  result = (3<<20) + (value[1] << 16) + (value[3] << 12) + (value[0] << 8);

 // pair

 else if(value[0] ==value[1])
  result = (2<<20) + (value[0]<<16) + (value[2]<<12) + (value[3]<<8) + (value[4]<<4);
 else if(value[1]==value[2])
  result = (2<<20) + (value[1]<<16) + (value[0]<<12) + (value[3]<<8) + (value[4]<<4);
 else if(value[2]==value[3])
  result = (2<<20) + (value[2]<<16) + (value[0]<<12) + (value[1]<<8) + (value[4]<<4);
 else if(value[3]==value[4])
  result=(2<<20) + (value[3]<<16) + (value[0]<<12) + (value[1]<<8) + (value[2]<<4);

 //high card
 else
  result = (1<<20) + (value[0] << 16) + (value[1] << 12) + (value[2] << 8)
  + (value[3] << 4) + value[4];

 return result;
}