Poker Hands

2013-04-21 Robert Zhang 更多博文 » 博客 » GitHub »

原文链接 http://huiming.io/2013/04/21/poker-hands.html
注:以下为加速网络访问所做的原文缓存,经过重新格式化,可能存在格式方面的问题,或偶有遗漏信息,请以原文为准。


<!--more-->

#include <cassert>
#include <iostream>
#include <vector>

using namespace std;

class Card {
public:
  char v;
  char t;
  Card(char av, char at) : v(av), t(at) {}
  Card() : v(0), t(0) {}
};

typedef enum {
  Unknown = 0,
  Big = 1,
  Pair,
  TwoPairs,
  Three,
  Sequence,
  SameColor,
  ThreeWithPair,
  Four,
  SequenceWithSameColor
} CardType;

typedef vector<vector<char> > TypeInfo;

#define VALUES "23456789TJQKA"

#ifdef DEBUG
  #include "../comm_headers/debug_helper.h"

  void SHOW_CARDS(const vector<Card> & cards) {
    for (int i = 0; i < cards.size(); i++) {
      DEBUG_OUT("%c%c ", VALUES[cards[i].v], cards[i].t);
    }
    DEBUG_OUT("n");
  }

  const char * TYPE_NAMES[] = {
    "Unknown",
    "Big",
    "Pair",
    "TwoPairs",
    "Three",
    "Sequence",
    "SameColor",
    "ThreeWithPair",
    "Four",
    "SequenceWithSameColor"
  };

  void SHOW_TYPE_INFO(CardType t, const TypeInfo & ti) {
    DEBUG_OUT("type: %sn", TYPE_NAMES[t]);
    for (int i = 1; i < ti.size(); i++) {
      DEBUG_OUT("%d: [", i);
      for (int j = 0; j < ti[i].size(); j++) {
        DEBUG_OUT("%c, ", VALUES[ti[i][j]]);
      }
      DEBUG_OUT("]n");
    }
  }

#else
  #define DEBUG_OUT(...) ((void)0)
  #define SHOW_CARDS(x) ((void)0)
  #define SHOW_TYPE_INFO(x, y) ((void)0)
#endif

inline char value(char v) {
  for (int i = 0; i < 13; i++) {
    if (VALUES[i] == v)
      return i;
  }
  assert(0 && "invalid value!");
  return -1;
}

bool load_cards(vector<Card> & cards) {
  cards.clear();
  cards.resize(5);
  for (int i = 0; i < 5; i++) {
    char v, t;
    if (!(cin >> v >> t))
      return false;
    v = value(v);
    Card c(v, t);
    int j = i - 1;
    for (; j >= 0; j--) {
      if (cards[j].v < v)
        cards[j + 1] = cards[j];
      else
        break;
    }
    cards[j + 1] = c;
  }
  SHOW_CARDS(cards);
  return true;
}

bool load_input(vector<Card> & b, vector<Card> & w) {
  return load_cards(b) && load_cards(w);
}

CardType type(const vector<Card> & cards, TypeInfo & info) {
  assert(5 == cards.size());
  bool same_color = true;
  char c = cards[0].t;
  int i;
  for (i = 1; i < 5; i++) {
    if (cards[i].t != c) {
      same_color = false;
      break;
    }
  }

  bool sequential = true;
  for (i = 0; i < 4; i++) {
    if (cards[i].v - cards[i + 1].v != 1) {
      sequential = false;
      break;
    }
  }

  if (same_color && sequential)
    return SequenceWithSameColor;

  if (sequential)
    return Sequence;

  if (same_color)
    return SameColor;

  info.resize(5);

  int n_pair = 0, n_three = 0, n_four = 0;
  char v = cards[0].v;
  int len = 1;
  for (i = 1; i <= 5; i++) {
    if (i != 5 && cards[i].v == v) {
      len++;
    }
    else {
      switch (len) {
        case 2:
          n_pair++;
          info[2].push_back(v);
          break;
        case 3:
          n_three++;
          info[3].push_back(v);
          break;
        case 4:
          n_four++;
          info[4].push_back(v);
          break;
      }
      if (i != 5) {
        v = cards[i].v;
        len = 1;
      }
    }
  }

  if (n_four)
    return Four;

  if (n_three)
    return n_pair ? ThreeWithPair : Three;

  if (n_pair) {
    vector<char> & excludes = info[2];
    for (i = 0; i < 5; i++) {
      char v = cards[i].v;
      bool excluded = false;
      for (int j = 0; j < excludes.size(); j++) {
        if (v == excludes[j]) {
          excluded = true;
          break;
        }
      }
      if (!excluded)
        info[1].push_back(v);
    }
    return n_pair == 2 ? TwoPairs : Pair;
  }

  return Big;
}

int compare_sequence(const vector<Card> & b, const vector<Card> & w) {
  assert(b.size() == w.size());
  for (int i = 0; i < b.size(); i++) {
    char r = b[i].v - w[i].v;
    if (r) {
      return r;
    }
  }
  return 0;
}

int compare(const vector<Card> & b, const vector<Card> & w) {
  TypeInfo tib, tiw;
  CardType tb = type(b, tib);
  CardType tw = type(w, tiw);
  SHOW_TYPE_INFO(tb, tib);
  SHOW_TYPE_INFO(tw, tiw);
  int r = tb - tw;
  if (!r) {
    switch (tb) {
      case Big: {
        r = compare_sequence(b, w);
        break;
      }
      case Pair: {
        r = tib[2][0] - tiw[2][0];
        if (!r) {
          for (int i = 0; i < tib[1].size(); i++) {
            r = tib[1][i] - tiw[1][i];
            if (r)
              break;
          }
        }
        break;
      }
      case TwoPairs: {
        r = (tib[2][0] - tiw[2][0]);
        if (!r)
          r = (tib[2][1] - tiw[2][1]);
        if (!r)
          r = (tib[1][0] - tiw[1][0]);
        break;
      }
      case Three: {
        r = tib[3][0] - tiw[3][0];
        break;
      }
      case Sequence: {
        r = b[0].v - w[0].v;
        break;
      }
      case SameColor: {
        r = compare_sequence(b, w);
        break;
      }
      case ThreeWithPair: {
        r = tib[3][0] - tiw[3][0];
        break;
      }
      case Four: {
        r = tib[4][0] - tiw[4][0];
        break;
      }
      case SequenceWithSameColor: {
        r = b[0].v - w[0].v;
        break;
      }
    }
  }
  return r;
}

int main() {
  vector<Card> b, w;
  while (load_input(b, w)) {
    int r = compare(b, w);
    if (r > 0)
      cout << "Black wins.";
    else if (r < 0)
      cout << "White wins.";
    else
      cout << "Tie.";
    cout << endl;
  }
  return 0;
}