Tuesday, September 14, 2010

ACM: 131 - The Psychic Poker Player

給玩家五張撲克牌,桌上有另五張的撲克牌,玩家可選擇捨棄0~5張牌,並從桌上依序補充同數量的牌。輸出可以達到的最大牌型(poker hand)

用了bool陣列去窮舉所有捨棄牌的方式,遞補相同數量的牌後,再一一檢查牌型。

CODE

#include <iostream>
#include <algorithm>
using namespace std;

enum { C, D, H, S };
enum { SF, FOAK, FH, FL, ST, TOAK, TP, OP, HC };
bool result[9]={0,0,0,0,0,0,0,0,0};
char line[9][16] = {"straight-flush", "four-of-a-kind", "full-house", 
"flush", "straight", "three-of-a-kind", "two-pairs", "one-pair", "highest-card"};

class poker{
public:
  int denom;
  int suit;
};

int next(bool *slot);
void check(poker *c);

int main(){
  int i, j, k;
  poker cards[2][5];
  char s[10][3];
  
  i = j = k = 0;
  while( scanf("%s", s[k]) != EOF ){
    if( s[k][0]>='2' && s[k][0]<='9' )
      cards[i][j].denom = s[k][0]-'0';
    else if( s[k][0] == 'A' )
      cards[i][j].denom = 1;
    else if( s[k][0] == 'T' )
      cards[i][j].denom = 10;
    else if( s[k][0] == 'J' )
      cards[i][j].denom = 11;
    else if( s[k][0] == 'Q' )
      cards[i][j].denom = 12;
    else if( s[k][0] == 'K' )
      cards[i][j].denom = 13;
    
    switch ( s[k][1] ){
      case 'C':
        cards[i][j].suit = C;
        break;
      case 'D':
        cards[i][j].suit = D;
        break;
      case 'H':
        cards[i][j].suit = H;
        break;
      case 'S':
        cards[i][j].suit = S;
        break;
    }//s[0]
    
    if( i==0 && j==4 ){
      i = 1;
      j = 0;
    }
    else if( i==1 && j==4 ){
      int count = 5;
      bool slot[5]={0, 0, 0, 0, 0};
      poker temp[5];
      while(1){
        j = 0;
        for(i=0; i<5; ++i){
          if( slot[i] )
            temp[i] = cards[1][j++];
          else
            temp[i] = cards[0][i];
        }
        check(temp);
        if( count == 0 )
          break;
        count = next(slot);
      }//search
      
      //output
      printf("Hand: ");
      for(i=0; i<5; ++i)
        printf("%s ", s[i]);
      printf("Deck: ");
      for(; i<10; ++i)
        printf("%s ", s[i]);
      printf("Best hand: ");
      for(i=0; i<9 && result[i]==0; ++i);
      printf("%s\n", line[i]);
      //initialize
      for(i=0; i<9; ++i)
        result[i] = 0;
      i = j = 0;
      k = -1;
    }
    else
      ++j;
    ++k;
  }//while get data
  
  return 0;
}

int next(bool *slot){
  if( slot[0] == 0 )
    slot[0] = 1;
  else{
    int i = 0;
    while( slot[i] == 1 )
      slot[i++] = 0;
    slot[i] = 1;
  }
  int count = 0;
  for(int i=0; i<5; ++i)
    if( slot[i] == 0 )
      ++count;
  return count;
}

void check(poker *c){
  int denoms[14]={0,0,0,0,0,0,0,0,0,0,0,0,0,0};
  int suits[4]={0,0,0,0};
  
  //sort
  int i, j, min, maxsuit = 0;
  for(i=0; i<5; ++i){
    min = i;
    for(j=i+1; j<5; ++j)
      if( c[j].denom < c[min].denom )
        min = j;
    swap(c[i], c[min]);
    ++denoms[ c[i].denom ];
    if( ++suits[ c[i].suit ] > maxsuit )
      maxsuit = suits[ c[i].suit ];
  }
  
  //find if straight
  bool straight = 0;
  for(i=1; i<5 && (c[i].denom == c[i-1].denom + 1); ++i);
  if( i == 5 )
    straight = 1;
  if(!straight && (c[0].denom == 1)){
    for(i=2; i<5 && (c[i].denom == c[i-1].denom + 1); ++i);
    if( i == 5 )
      straight = 1;
  }
  if( straight ){
    if( maxsuit == 5 )
      result[SF] = 1; //straight flush
    else
      result[ST] = 1; //straight
  }
  if( maxsuit == 5 )
    result[FL] = 1; //flush
  
  int three = 0, two = 0;
  for(i=1; i<=13; ++i){
    switch ( denoms[i] ){
      case 4:
        result[FOAK] = 1; //four of a kind
        break;
      case 3:
        result[TOAK] = 1; //three of a kind
        ++three;
        break;
      case 2:
        ++two;
    }
  }//i
  
  if( three == 1 && two == 1 )
    result[FH] = 1; // full house
  else if( two == 2 )
    result[TP] = 1; //two pairs
  else if( two == 1 )
    result[OP] = 1; //one pair
  else
    result[HC] = 1; //highest card
}

No comments:

Post a Comment