Language: C++
/* 2.8.8 Yahtzee PC/UVa IDs: 110208/10149, Popularity: C, Success rate: average Level: 3 To build using Visucal Studio 2008: cl -EHsc -O2 yahtzee.cpp */ #include <iostream> #ifdef DEBUG #include <iomanip> #endif #include <vector> #include <map> #include <algorithm> #include <numeric> #ifdef __ELAPSED_TIME__ #include <ctime> #endif using namespace std; enum categories { ct_not_applied = -1, ct_ones, ct_twos, ct_threes, ct_fours, ct_fives, ct_sixes, ct_chance, ct_three_of_a_kind, ct_four_of_a_kind, ct_five_of_a_kind, ct_short_straight, ct_long_straight, ct_full_house }; const int nr_dies = 5; // number of dies const int nr_rounds = 13; // number of rounds const int nr_categories = ct_full_house - ct_ones + 1; // number of categories const int min_sum_for_bonus = 63; // min. sum of first six categories for bonus const int bonus_point = 35; // bonus point int category_chance(const vector<int>& dies) // sum of all dies { return accumulate(dies.begin(), dies.end(), 0); } int category_three_of_a_kind(const vector<int>& dies) // sum of all dies, provided at least three have same value { // note that dies is sorted in ascending order for (int i = 0; i < nr_dies - 2; i++) if (dies[i] == dies[i + 1] && dies[i + 1] == dies[i + 2]) return category_chance(dies); return 0; } int category_four_of_a_kind(const vector<int>& dies) // sum of all dies, provided at least four have same value { // note that dies is sorted in ascending order int j = (dies[0] == dies[1]) ? nr_dies - 2 : nr_dies - 1; for (int i = 1; i < j; i++) if (dies[i] != dies[i + 1]) return 0; return category_chance(dies); } int category_five_of_a_kind(const vector<int>& dies) // 50 points, provided all five dies have same value { // note that dies is sorted in ascending order return (dies[0] == dies[4]) ? 50 : 0; } int category_short_straight(const vector<int>& dies) // 25 points, provided four of the dies form a sequence { int j = (dies[0] + 1 == dies[1]) ? nr_dies - 2 : nr_dies - 1; for (int i = 1; i < j; i++) if (dies[i] + 1 != dies[i + 1]) return 0; return 25; } int category_long_straight(const vector<int>& dies) // 35 points, provided all dies form a sequence { for (int i = 0; i < nr_dies - 1; i++) if (dies[i] + 1 != dies[i + 1]) return 0; return 35; } int category_full_house(const vector<int>& dies) // 40 points, provided three of the dies are equal and // the other two dies are also equal { if (dies[0] != dies[1]) // the first two must be equal return 0; if (dies[1] == dies[2]) // the first three are equal return (dies[3] == dies[4]) ? 40 : 0; // the last two must be equal else return (dies[2] == dies[3] && dies[3] == dies[4]) ? 40 : 0; // the last three must be equal } int category_numbers(const vector<int>& dies, int n) { return n * count(dies.begin(), dies.end(), n); } int category_ones(const vector<int>& dies) // sum of all ones thrown { return category_numbers(dies, 1); } int category_twos(const vector<int>& dies) // sum of all twos thrown { return category_numbers(dies, 2); } int category_threes(const vector<int>& dies) // sum of all threes thrown { return category_numbers(dies, 3); } int category_fours(const vector<int>& dies) // sum of all fours thrown { return category_numbers(dies, 4); } int category_fives(const vector<int>& dies) // sum of all fives thrown { return category_numbers(dies, 5); } int category_sixes(const vector<int>& dies) // sum of all sixes thrown { return category_numbers(dies, 6); } void caluculate_applicable_scores(const vector<int>& dies, vector<int>& scores) { typedef int (*category_function)(const vector<int>&); const category_function category_functions[] = { category_ones, category_twos, category_threes, category_fours, category_fives, category_sixes, category_chance, category_three_of_a_kind, category_four_of_a_kind, category_five_of_a_kind, category_short_straight, category_long_straight, category_full_house }; for (int i = ct_ones; i <= ct_full_house; i++) { int score = category_functions[i](dies); if (score) scores[i] = score; } } inline int get_score_index(int category) { return 1 << (category + 16); } inline int get_score_index(int category, int score) // score index for the first six categories { /* if (score > min_sum_for_bonus) score = min_sum_for_bonus; */ return 1 << (category + 16) | score; } inline int get_category_bitmap(int index) { return index >> 16; } inline int get_score_for_bonus(int index) { return index & 0xffff; } int get_applied_score(unsigned long long score, int category, const vector< vector<int> >& applicable_scores) { int round = static_cast<int>((score >> (category * 4)) & 0xf); return (round == 0xf) ? 0 /* not applied */ : applicable_scores[round][category]; } inline int get_total_of_score(unsigned long long score) { return static_cast<int>((score >> 52) & 0xfff); } unsigned long long set_score(int round, int category, const vector< vector<int> >& applicable_scores) { unsigned long long score = 0x000fffffffffffffULL; score &= ~(static_cast<unsigned long long>(0xf) << (category * 4)); score |= static_cast<unsigned long long>(round) << (category * 4); score |= static_cast<unsigned long long>(applicable_scores[round][category]) << 52; return score; } unsigned long long change_score(unsigned long long score, int round, int category, int s) { score &= ~(static_cast<unsigned long long>(0xf) << (category * 4)); score |= static_cast<unsigned long long>(round) << (category * 4); score &= 0x000fffffffffffffULL; score |= static_cast<unsigned long long>(s) << 52; return score; } void add_to_scores(int index, unsigned long long score, map<int, unsigned long long>& scores) { map<int, unsigned long long>::iterator i = scores.find(index); if (i != scores.end()) { if (get_total_of_score(i->second) < get_total_of_score(score)) i->second = score; } else scores.insert(make_pair(index, score)); } bool read_rounds_of_dies(vector< vector<int> >& applicable_scores) { for (int i = 0; i < nr_rounds; i++) { // read the values of thirteen rounds vector<int> dies(nr_dies); // values of the five dies thrown, sorted in ascending order for (int j = 0; j < nr_dies; j++) { // read the values of the five dies if (!(cin >> dies[j])) return false; // end of input } sort(dies.begin(), dies.end()); caluculate_applicable_scores(dies, applicable_scores[i]); } return true; } #ifdef DEBUG void print_scores(const map<int, unsigned long long>& scores) { map<int, unsigned long long>::const_iterator iend = scores.end(); for (map<int, unsigned long long>::const_iterator i = scores.begin(); i != iend; ++i) cerr << hex << setw(4) << setfill('0') << get_category_bitmap(i->first) << '-' << dec << setw(4) << setfill(' ') << get_score_for_bonus(i->first) << ": " << get_total_of_score(i->second) << endl; cerr << endl; } #endif void caluculate_scores(vector< vector<int> >& applicable_scores, vector< map<int, unsigned long long> >& scores) { for (int i = 0; i < nr_rounds; i++) { map<int, unsigned long long>& current_scores = scores[i % 2]; map<int, unsigned long long>& previous_scores = scores[(i + 1) % 2]; current_scores = previous_scores; for (int j = 0; j < nr_categories; j++) { if (applicable_scores[i][j] == -1) // not applied to any categories continue; int pi, ci; // previous and current indices unsigned long long ps, cs; // prevous and current scores // insert or update a pair of category and its score on its own ci = (j < ct_chance) ? get_score_index(j, applicable_scores[i][j]) : get_score_index(j); cs = set_score(i, j, applicable_scores); add_to_scores(ci, cs, current_scores); // add the score to the existing pairs of categories and thier scores map<int, unsigned long long>::iterator k, kend = previous_scores.end(); for (k = previous_scores.begin(); k != kend; ++k) { pi = k->first; ps = k->second; int ts = get_total_of_score(ps); // totoal of the previous score // score for category j of the previous score int as = (pi & get_score_index(j)) ? // category j is applied to any of the previous rounds get_applied_score(ps, j, applicable_scores) : 0; if (j > ct_sixes) { // replace category j with current round i and update the total score cs = change_score(ps, i, j, ts + applicable_scores[i][j] - as); add_to_scores(pi | get_score_index(j), cs, current_scores); } else { // modifying the socre for category j of the prevous score also // entails updating the lower 16-bits of index. ci = get_score_index(j, get_score_for_bonus(pi) + applicable_scores[i][j] - as); ci |= get_category_bitmap(pi) << 16; cs = change_score(ps, i, j, ts + applicable_scores[i][j] - as); add_to_scores(ci, cs, current_scores); } } } #ifdef DEBUG cerr << i + 1 << " rounds, " << current_scores.size() << " scores\n"; // print_scores(current_scores); #endif } } int get_max_score(map<int, unsigned long long>& scores, pair<int, unsigned long long>& s) { int max_ts = -1; map<int, unsigned long long>::const_iterator iend = scores.end(); for (map<int, unsigned long long>::const_iterator i = scores.begin(); i != iend; ++i) { int ts = get_total_of_score(i->second); if (get_score_for_bonus(i->first) >= min_sum_for_bonus) ts += bonus_point; // a bonus of 35 points if the sum of the first six categories is // 63 or greater if (max_ts < ts) { max_ts = ts; s = *i; } } return max_ts; } void print_scores(const pair<int, unsigned long long>& s, const vector< vector<int> >& applicable_scores) { int ts = get_total_of_score(s.second); unsigned long long ri = s.second; for (int i = 0; i < nr_categories; i++, ri >>= 4) { // print the score for each category int r = (ri & 0xf); cout << ((r != 0x0f) ? applicable_scores[r][i] : 0) << ' '; } // print the bonus score if (get_score_for_bonus(s.first) >= min_sum_for_bonus) { cout << "35 "; ts += bonus_point; } else cout << "0 "; cout << ts << endl; } int main(int /* argc */, char ** /* argv */) { #ifdef __ELAPSED_TIME__ clock_t start = clock(); #endif while (true) { vector< vector<int> > applicable_scores(nr_rounds, vector<int>(nr_categories, -1)); // applicable_scores[i][j] is the score when the j-th category is // applied to the i-th round, // or -1 if the j-th category cannot be applied. if (!read_rounds_of_dies(applicable_scores)) break; vector< map<int, unsigned long long> > scores(2); /* key is an index whose: higher 16-bits are bitmaps of applied categories, in which i-th bit is set if the i-th categoriy from categories enumeration is applied. lower 16-bits are the sum of first six categories' (i.e., ones, twos, threes, fours, fives, and sixes) scores. value is the score: bit (4 * i) - bit (4 * i + 3) is the round index if the i-th category is applied to the round, or 0xf if it is not applied. bit 52 - bit 63 is the total scores. */ caluculate_scores(applicable_scores, scores); map<int, unsigned long long>& current_scores = scores[(nr_rounds - 1) % 2]; pair<int, unsigned long long> s; get_max_score(current_scores, s); print_scores(s, applicable_scores); } #ifdef __ELAPSED_TIME__ cerr << "elapsed time = " << static_cast<double>(clock() - start) / CLOCKS_PER_SEC << " sec.\n"; #endif return 0; }
No comments:
Post a Comment