Online Judge | Problem Set | Authors | Online Contests | User | ||||||
---|---|---|---|---|---|---|---|---|---|---|
Web Board Home Page F.A.Qs Statistical Charts | Current Contest Past Contests Scheduled Contests Award Contest |
写了近14K代码终于一次AC了#include <cassert> #include <stdexcept> #include <string> #include <iostream> #include <vector> #include <algorithm> using namespace std; struct Card { class Rank { friend bool operator<(const Rank &, const Rank &); friend bool operator>(const Rank &, const Rank &); friend bool operator<=(const Rank &, const Rank &); friend bool operator>=(const Rank &, const Rank &); friend bool operator==(const Rank &, const Rank &); friend bool operator!=(const Rank &, const Rank &); public: Rank() {} Rank(const Rank &rhs) : value(rhs.value) {} operator char() const { return all_representations[value]; } Rank(char representation) { size_t location = all_representations.find(representation); if (location == string::npos) { throw invalid_argument("Invalid rank"); } value = location; } explicit Rank(int v) : value(v) { if (value >= number_of_distinct_ranks) { throw invalid_argument("Invalid rank"); } } int get_value() const { return value; } static const int number_of_distinct_ranks; Rank &operator++(); Rank &operator--(); private: int value; static const string all_representations; } rank; enum Suit {club, diamond, heart, spade} suit; Card() {} Card(const Card &rhs) : rank(rhs.rank), suit(rhs.suit) {} Card(const char *representation) : rank(representation[0]) { switch (representation[1]) { case 'C': suit = club; break; case 'D': suit = diamond; break; case 'H': suit = heart; break; case 'S': suit = spade; break; default: throw new invalid_argument("Invalid suit"); } } }; const string Card::Rank::all_representations("23456789TJQKA"); const int Card::Rank::number_of_distinct_ranks = 13; bool operator<(const Card::Rank &lhs, const Card::Rank &rhs) { return lhs.value < rhs.value; } bool operator>(const Card::Rank &lhs, const Card::Rank &rhs) { return lhs.value > rhs.value; } bool operator<=(const Card::Rank &lhs, const Card::Rank &rhs) { return lhs.value <= rhs.value; } bool operator>=(const Card::Rank &lhs, const Card::Rank &rhs) { return lhs.value >= rhs.value; } bool operator==(const Card::Rank &lhs, const Card::Rank &rhs) { return lhs.value == rhs.value; } bool operator!=(const Card::Rank &lhs, const Card::Rank &rhs) { return lhs.value != rhs.value; } bool operator==(const Card &lhs, const Card &rhs) { return lhs.suit == rhs.suit && lhs.rank == rhs.rank; } bool operator!=(const Card &lhs, const Card &rhs) { return lhs.suit != rhs.suit || lhs.rank != rhs.rank; } bool operator<(const Card &lhs, const Card &rhs) { return lhs.rank < rhs.rank; } bool operator>(const Card &lhs, const Card &rhs) { return lhs.rank > rhs.rank; } bool operator<=(const Card &lhs, const Card &rhs) { return lhs.rank <= rhs.rank; } bool operator>=(const Card &lhs, const Card &rhs) { return lhs.rank >= rhs.rank; } class Hand { public: struct Ranking { enum Category {high_card, one_pair, two_pairs, three_of_a_kind, straight, flush, full_house, four_of_a_kind, straight_flush} category; vector<Card::Rank> tie_breakers; Ranking &operator++(); Ranking &operator--(); void dump() const { cerr << category << ' '; for (vector<Card::Rank>::const_iterator p = tie_breakers.begin(); p != tie_breakers.end(); ++p) { cerr << *p << ' '; } cerr << endl; } private: void fill_remaining_tie_breakers(int start, int end); }; static const int number_of_cards = 5; template<class Iterator> Hand(Iterator begin) { for (int count = 0; count < number_of_cards; ++count) { for (int index = 0; index < count; ++index) { if (cards[index] == *begin) { throw new invalid_argument("A hand must not contain two cards which are the same."); } } cards[count] = *begin; ++begin; } }; Ranking calculate_ranking() const; int calculate_value() const; private: Card cards[number_of_cards]; }; bool operator==(const Hand::Ranking &a, const Hand::Ranking &b); bool operator!=(const Hand::Ranking &a, const Hand::Ranking &b); int main() { Card cards[Hand::number_of_cards]; for (int count = 0; count < Hand::number_of_cards; ++count) { string input; cin >> input; cards[count] = input.c_str(); } cout << Hand(cards).calculate_value() << '\n'; } int Hand::calculate_value() const { const Ranking ranking = calculate_ranking(); int ans = 1; const Card cards_of_lowest_hand[] = {"3S", "7S", "2C", "4S", "5H"}; for (Ranking iterator = Hand(cards_of_lowest_hand).calculate_ranking(); iterator != ranking; ++iterator) { //iterator.dump(); ++ans; } return ans; } Hand::Ranking Hand::calculate_ranking() const { Ranking answer; int rank_counts[Card::Rank::number_of_distinct_ranks] = {}; bool being_flush = true; for (int i = 0; i < number_of_cards; ++i) { ++rank_counts[cards[i].rank.get_value()]; if (cards[i].suit != cards[0].suit) { being_flush = false; } } bool being_straight = false; for (int i = 0; i + 5 <= Card::Rank::number_of_distinct_ranks; ++i) { bool starting_straight = true; for (int j = i; j < i + 5; ++j) { if (!rank_counts[j]) { starting_straight = false; } } if (starting_straight) { being_straight = true; answer.tie_breakers.push_back(Card::Rank(i + 4)); } } // 12345 if (rank_counts[12]) { bool starting_straight = true; for (int i = 0; i < 4; ++i) { if (!rank_counts[i]) { starting_straight = false; } } if (starting_straight) { being_straight = true; answer.tie_breakers.push_back(Card::Rank(3)); } } if (being_straight) { answer.category = being_flush ? Ranking::straight_flush : Ranking::straight; } else { int maximum_number_of_cards_in_a_rank = 0; for (int i = 0; i < Card::Rank::number_of_distinct_ranks; ++i) { maximum_number_of_cards_in_a_rank = max(maximum_number_of_cards_in_a_rank, rank_counts[i]); } for (int i = maximum_number_of_cards_in_a_rank; i >= 1; --i) { for (int j = Card::Rank::number_of_distinct_ranks - 1; j >= 0; --j) { if (rank_counts[j] == i) { answer.tie_breakers.push_back(Card::Rank(j)); } } } switch (maximum_number_of_cards_in_a_rank) { case 4: answer.category = Ranking::four_of_a_kind; break; case 3: answer.category = answer.tie_breakers.size() == 2 ? Ranking::full_house : Ranking::three_of_a_kind; break; case 2: answer.category = answer.tie_breakers.size() == 3 ? Ranking::two_pairs : Ranking::one_pair; break; case 1: answer.category = being_flush ? Ranking::flush : Ranking::high_card; break; } } return answer; } Hand::Ranking &Hand::Ranking::operator++() { switch (category) { case straight: case straight_flush: try { ++tie_breakers[0]; } catch (overflow_error &) { if (category == straight) { category = flush; const Card::Rank lowest_ranks_of_a_hand[] = {'7', '5', '4', '3', '2'}; tie_breakers.assign(&lowest_ranks_of_a_hand[0], &lowest_ranks_of_a_hand[sizeof lowest_ranks_of_a_hand / sizeof lowest_ranks_of_a_hand[0]]); } else { throw; } } break; case four_of_a_kind: case full_house: try { ++tie_breakers[1]; if (tie_breakers[1] == tie_breakers[0]) ++tie_breakers[1]; } catch (overflow_error &) { try { ++tie_breakers[0]; tie_breakers[1] = '2'; } catch (overflow_error &) { if (category == four_of_a_kind) { category = straight_flush; tie_breakers.assign(1, '5'); } else { category = four_of_a_kind; tie_breakers[0] = '2'; tie_breakers[1] = '3'; } } } break; case three_of_a_kind: ++tie_breakers[2]; if (tie_breakers[2] == tie_breakers[0]) { ++tie_breakers[2]; } if (tie_breakers[2] == tie_breakers[1]) { try { ++tie_breakers[1]; if (tie_breakers[1] == tie_breakers[0]) ++tie_breakers[1]; fill_remaining_tie_breakers(2, 3); } catch (overflow_error &) { try { ++tie_breakers[0]; } catch (overflow_error &) { category = straight; tie_breakers.assign(1, '5'); } fill_remaining_tie_breakers(1, 3); } } break; case two_pairs: try { ++tie_breakers[2]; if (tie_breakers[2] == tie_breakers[1]) ++tie_breakers[2]; if (tie_breakers[2] == tie_breakers[0]) ++tie_breakers[2]; } catch (overflow_error &) { ++tie_breakers[1]; if (tie_breakers[1] == tie_breakers[0]) { try { ++tie_breakers[0]; tie_breakers[1] = '2'; fill_remaining_tie_breakers(2, 3); } catch (overflow_error &) { category = three_of_a_kind; tie_breakers[0] = '2'; tie_breakers[1] = '4'; tie_breakers[2] = '3'; } } else { fill_remaining_tie_breakers(2, 3); } } break; case one_pair: try { int i; for (i = 3; i >= 1; --i) { ++tie_breakers[i]; if (tie_breakers[i] == tie_breakers[0]) { ++tie_breakers[i]; } if (i == 1 || tie_breakers[i] != tie_breakers[i - 1]) break; } fill_remaining_tie_breakers(i + 1, 4); } catch (overflow_error &) { try { ++tie_breakers[0]; fill_remaining_tie_breakers(1, 4); } catch (overflow_error &) { category = two_pairs; tie_breakers.resize(3); tie_breakers[0] = '3'; tie_breakers[1] = '2'; tie_breakers[2] = '4'; } } break; case high_card: case flush: try { int i; for (i = 4; i >= 0; --i) { ++tie_breakers[i]; if (i == 0 || tie_breakers[i] != tie_breakers[i - 1]) break; } fill_remaining_tie_breakers(i + 1, 5); // prevent generating snake Card sample_cards[number_of_cards]; for (int i = 0; i < number_of_cards; ++i) { sample_cards[i].suit = Card::club; sample_cards[i].rank = tie_breakers[i]; } Ranking sample_ranking = Hand(sample_cards).calculate_ranking(); if (sample_ranking.category == straight_flush) { ++*this; } } catch (overflow_error &) { if (category == high_card) { category = one_pair; tie_breakers.resize(4); tie_breakers[0] = '2'; fill_remaining_tie_breakers(1, 4); } else { category = full_house; tie_breakers.resize(2); tie_breakers[0] = '2'; tie_breakers[1] = '3'; } } break; default: assert(false); } return *this; } bool operator==(const Hand::Ranking &lhs, const Hand::Ranking &rhs) { return lhs.category == rhs.category && lhs.tie_breakers == rhs.tie_breakers; } bool operator!=(const Hand::Ranking &lhs, const Hand::Ranking &rhs) { return lhs.category != rhs.category || lhs.tie_breakers != rhs.tie_breakers; } Card::Rank &Card::Rank::operator++() { if (value == number_of_distinct_ranks - 1) { throw overflow_error("Rank already maximum"); } ++value; return *this; } void Hand::Ranking::fill_remaining_tie_breakers(int start, int end) { if (end > start) { tie_breakers[end - 1] = '2'; for (int i = end - 1; i >= start; --i) { for (int j = start - 1; j >= 0; --j) { if (tie_breakers[i] == tie_breakers[j]) { ++tie_breakers[i]; } } if (i != start) { tie_breakers[i - 1] = tie_breakers[i]; ++tie_breakers[i - 1]; } } } } 注释: Card即是牌,每张牌有rank同suit,分别属Card::Rank及Card::Suit。 Card::Rank用来代表牌的点数,能自动转换为char(即2、3、4、……、Q、K、A等)及由char转换,亦可用get_value来取得其强度。当中的operator++能直接增加一点,如果超标则抛出异常。 Card::Suit代表花色,只是简单的enum。 Hand即是手牌,有5张牌。calculate_value是求答案的方法,而calculate_ranking则返回一般玩家所使用的牌力描述(例如同花顺A头、85对带3、AJ632花等等)。 Hand::Ranking有operator++,用来找出下一组比这组大的牌,例如23457下一组为23467,75对带A下组是76对带2,同花顺A头下组会抛出异常。所以calculate_value只需先制造最少的Ranking,然后不断++到找到为止。 Followed by: Post your reply here: |
All Rights Reserved 2003-2013 Ying Fuchen,Xu Pengcheng,Xie Di
Any problem, Please Contact Administrator