library

This documentation is automatically generated by online-judge-tools/verification-helper

View the Project on GitHub maspypy/library

:warning: other/poker.hpp

Depends on

Code

#include "other/bit.hpp"

namespace poker {

// rank: 0=2, 1=3, ..., 8=T, 9=J, 10=Q, 11=K, 12=A
// suit: 0=C, 1=D, 2=H, 3=S
// card = 4 * rank + suit

enum class Category : u8 {
  HIGH_CARD,
  ONE_PAIR,
  TWO_PAIR,
  THREE_OF_A_KIND,
  STRAIGHT,
  FLUSH,
  FULL_HOUSE,
  FOUR_OF_A_KIND,
  STRAIGHT_FLUSH
};

inline constexpr array<string_view, 9> CATEGORY_NAMES = {
    "HIGH_CARD", "ONE_PAIR",   "TWO_PAIR",       "THREE_OF_A_KIND", "STRAIGHT",
    "FLUSH",     "FULL_HOUSE", "FOUR_OF_A_KIND", "STRAIGHT_FLUSH",
};

constexpr string_view RANKS = "23456789TJQKA";
constexpr string_view SUITS = "CDHS";

u8 make_card(int rank, int suit) {
  assert(0 <= rank && rank < 13);
  return u8(rank << 2 | suit);
}
int rank(u8 card) { return card >> 2; }
int suit(u8 card) { return card & 3; }
// 2C,3C,...,9C,TC,JC,QC,KC,AC
u8 from_string(string X) {
  return make_card(RANKS.find(X[0]), SUITS.find(X[1]));
}
string to_string(u8 card) {
  string result;
  result += RANKS[rank(card)];
  result += SUITS[suit(card)];
  return result;
}

constexpr array<int8_t, 1 << 13> make_straight_high_table() {
  array<int8_t, 1 << 13> table{};
  for (auto& x : table) x = -1;
  // 23456, 34567, ..., TJQKA
  for (int low = 0; low <= 8; ++low) {
    table[0b11111 << low] = low + 4;
  }
  // A2345: 5-high straight
  table[(1 << 12) | 0b1111] = 3;
  return table;
}

inline constexpr auto STRAIGHT_HIGH = make_straight_high_table();

u32 category_high(Category X, u32 a = 0, u32 b = 0, u32 c = 0, u32 d = 0,
                  u32 e = 0) {
  return (u32(X) << 20) | (a << 16) | ((b) << 12) | (c << 8) | (d << 4) | (e);
}
u32 category_distinct(Category X, u32 mask) {
  u32 value = u32(X) << 20;
  int shift = 16;
  while (mask) {
    int r = topbit(mask);
    value |= topbit(mask) << shift;
    mask ^= 1u << r, shift -= 4;
  }
  return value;
}

u32 evaluate5(u8 c0, u8 c1, u8 c2, u8 c3, u8 c4) {
  int r0 = rank(c0), r1 = rank(c1), r2 = rank(c2), r3 = rank(c3), r4 = rank(c4);
  bool flush = ((c0 ^ c1) | (c0 ^ c2) | (c0 ^ c3) | (c0 ^ c4)) % 4 == 0;
  u32 mask = (1u << r0) | (1u << r1) | (1u << r2) | (1u << r3) | (1u << r4);
  const u64 C = (1ULL << (4 * r0)) + (1ULL << (4 * r1)) + (1ULL << (4 * r2)) +
                (1ULL << (4 * r3)) + (1ULL << (4 * r4));

  if (popcnt(mask) == 5) {
    int s = STRAIGHT_HIGH[mask];
    if (flush) {
      if (s >= 0) {
        return category_high(Category::STRAIGHT_FLUSH, s);
      }
      return category_distinct(Category::FLUSH, mask);
    }
    if (s >= 0) {
      return category_high(Category::STRAIGHT, s);
    }
    return category_distinct(Category::HIGH_CARD, mask);
  }

  int quad = -1;
  int trip = -1;
  int high_pair = -1;
  int low_pair = -1;
  int singles[3];
  int p = 0;

  for (int r = 12; r >= 0; --r) {
    int cnt = (C >> (4 * r)) & 15;
    if (cnt == 4) {
      quad = r;
    }
    elif (cnt == 3) { trip = r; }
    elif (cnt == 2) { (high_pair == -1 ? high_pair : low_pair) = r; }
    elif (cnt == 1) { singles[p++] = r; }
  }

  if (quad >= 0) {
    return category_high(Category::FOUR_OF_A_KIND, quad, singles[0]);
  }

  if (trip >= 0 && high_pair >= 0) {
    return category_high(Category::FULL_HOUSE, trip, high_pair);
  }

  if (trip >= 0) {
    return category_high(Category::THREE_OF_A_KIND, trip, singles[0],
                         singles[1]);
  }

  if (low_pair >= 0) {
    return category_high(Category::TWO_PAIR, high_pair, low_pair, singles[0]);
  }
  return category_high(Category::ONE_PAIR, high_pair, singles[0], singles[1],
                       singles[2]);
}
}  // namespace poker
#line 1 "other/poker.hpp"

#line 2 "other/bit.hpp"

int popcnt(int x) { return __builtin_popcount(x); }
int popcnt(u32 x) { return __builtin_popcount(x); }
int popcnt(ll x) { return __builtin_popcountll(x); }
int popcnt(u64 x) { return __builtin_popcountll(x); }
int popcnt_sgn(int x) { return (__builtin_parity(unsigned(x)) & 1 ? -1 : 1); }
int popcnt_sgn(u32 x) { return (__builtin_parity(x) & 1 ? -1 : 1); }
int popcnt_sgn(ll x) { return (__builtin_parityll(x) & 1 ? -1 : 1); }
int popcnt_sgn(u64 x) { return (__builtin_parityll(x) & 1 ? -1 : 1); }
// (0, 1, 2, 3, 4) -> (-1, 0, 1, 1, 2)
int topbit(int x) { return (x == 0 ? -1 : 31 - __builtin_clz(x)); }
int topbit(u32 x) { return (x == 0 ? -1 : 31 - __builtin_clz(x)); }
int topbit(ll x) { return (x == 0 ? -1 : 63 - __builtin_clzll(x)); }
int topbit(u64 x) { return (x == 0 ? -1 : 63 - __builtin_clzll(x)); }
// (0, 1, 2, 3, 4) -> (-1, 0, 1, 0, 2)
int lowbit(int x) { return (x == 0 ? -1 : __builtin_ctz(x)); }
int lowbit(u32 x) { return (x == 0 ? -1 : __builtin_ctz(x)); }
int lowbit(ll x) { return (x == 0 ? -1 : __builtin_ctzll(x)); }
int lowbit(u64 x) { return (x == 0 ? -1 : __builtin_ctzll(x)); }

template <typename T>
T kth_bit(int k) {
  return T(1) << k;
}
template <typename T>
bool has_kth_bit(T x, int k) {
  return x >> k & 1;
}

template <typename UINT>
struct all_bit {
  UINT s;
  all_bit(UINT s) : s(s) {}
  struct iter {
    UINT s;
    int operator*() const { return lowbit(s); }
    void operator++() { s &= s - 1; }
    bool operator!=(nullptr_t) const { return s; }
  };
  iter begin() const { return {s}; }
  nullptr_t end() const { return nullptr; }
};

template <typename UINT>
struct all_subset {
  UINT s;
  all_subset(UINT s) : s(s) {}
  struct iter {
    UINT s, t;
    bool done = false;
    UINT operator*() const { return t; }
    void operator++() {
      done = (t == 0);
      t = (t - 1) & s;
    }
    bool operator!=(nullptr_t) const { return !done; }
  };
  iter begin() const { return {s, s}; }
  nullptr_t end() const { return nullptr; }
};

constexpr u64 full_mask(int n) { return n == 64 ? -1ULL : (1ULL << n) - 1; }
#line 3 "other/poker.hpp"

namespace poker {

// rank: 0=2, 1=3, ..., 8=T, 9=J, 10=Q, 11=K, 12=A
// suit: 0=C, 1=D, 2=H, 3=S
// card = 4 * rank + suit

enum class Category : u8 {
  HIGH_CARD,
  ONE_PAIR,
  TWO_PAIR,
  THREE_OF_A_KIND,
  STRAIGHT,
  FLUSH,
  FULL_HOUSE,
  FOUR_OF_A_KIND,
  STRAIGHT_FLUSH
};

inline constexpr array<string_view, 9> CATEGORY_NAMES = {
    "HIGH_CARD", "ONE_PAIR",   "TWO_PAIR",       "THREE_OF_A_KIND", "STRAIGHT",
    "FLUSH",     "FULL_HOUSE", "FOUR_OF_A_KIND", "STRAIGHT_FLUSH",
};

constexpr string_view RANKS = "23456789TJQKA";
constexpr string_view SUITS = "CDHS";

u8 make_card(int rank, int suit) {
  assert(0 <= rank && rank < 13);
  return u8(rank << 2 | suit);
}
int rank(u8 card) { return card >> 2; }
int suit(u8 card) { return card & 3; }
// 2C,3C,...,9C,TC,JC,QC,KC,AC
u8 from_string(string X) {
  return make_card(RANKS.find(X[0]), SUITS.find(X[1]));
}
string to_string(u8 card) {
  string result;
  result += RANKS[rank(card)];
  result += SUITS[suit(card)];
  return result;
}

constexpr array<int8_t, 1 << 13> make_straight_high_table() {
  array<int8_t, 1 << 13> table{};
  for (auto& x : table) x = -1;
  // 23456, 34567, ..., TJQKA
  for (int low = 0; low <= 8; ++low) {
    table[0b11111 << low] = low + 4;
  }
  // A2345: 5-high straight
  table[(1 << 12) | 0b1111] = 3;
  return table;
}

inline constexpr auto STRAIGHT_HIGH = make_straight_high_table();

u32 category_high(Category X, u32 a = 0, u32 b = 0, u32 c = 0, u32 d = 0,
                  u32 e = 0) {
  return (u32(X) << 20) | (a << 16) | ((b) << 12) | (c << 8) | (d << 4) | (e);
}
u32 category_distinct(Category X, u32 mask) {
  u32 value = u32(X) << 20;
  int shift = 16;
  while (mask) {
    int r = topbit(mask);
    value |= topbit(mask) << shift;
    mask ^= 1u << r, shift -= 4;
  }
  return value;
}

u32 evaluate5(u8 c0, u8 c1, u8 c2, u8 c3, u8 c4) {
  int r0 = rank(c0), r1 = rank(c1), r2 = rank(c2), r3 = rank(c3), r4 = rank(c4);
  bool flush = ((c0 ^ c1) | (c0 ^ c2) | (c0 ^ c3) | (c0 ^ c4)) % 4 == 0;
  u32 mask = (1u << r0) | (1u << r1) | (1u << r2) | (1u << r3) | (1u << r4);
  const u64 C = (1ULL << (4 * r0)) + (1ULL << (4 * r1)) + (1ULL << (4 * r2)) +
                (1ULL << (4 * r3)) + (1ULL << (4 * r4));

  if (popcnt(mask) == 5) {
    int s = STRAIGHT_HIGH[mask];
    if (flush) {
      if (s >= 0) {
        return category_high(Category::STRAIGHT_FLUSH, s);
      }
      return category_distinct(Category::FLUSH, mask);
    }
    if (s >= 0) {
      return category_high(Category::STRAIGHT, s);
    }
    return category_distinct(Category::HIGH_CARD, mask);
  }

  int quad = -1;
  int trip = -1;
  int high_pair = -1;
  int low_pair = -1;
  int singles[3];
  int p = 0;

  for (int r = 12; r >= 0; --r) {
    int cnt = (C >> (4 * r)) & 15;
    if (cnt == 4) {
      quad = r;
    }
    elif (cnt == 3) { trip = r; }
    elif (cnt == 2) { (high_pair == -1 ? high_pair : low_pair) = r; }
    elif (cnt == 1) { singles[p++] = r; }
  }

  if (quad >= 0) {
    return category_high(Category::FOUR_OF_A_KIND, quad, singles[0]);
  }

  if (trip >= 0 && high_pair >= 0) {
    return category_high(Category::FULL_HOUSE, trip, high_pair);
  }

  if (trip >= 0) {
    return category_high(Category::THREE_OF_A_KIND, trip, singles[0],
                         singles[1]);
  }

  if (low_pair >= 0) {
    return category_high(Category::TWO_PAIR, high_pair, low_pair, singles[0]);
  }
  return category_high(Category::ONE_PAIR, high_pair, singles[0], singles[1],
                       singles[2]);
}
}  // namespace poker
Back to top page