-
-
Save jchughes/b7ac71568b7ade09eb3a to your computer and use it in GitHub Desktop.
Old poker hand evaluator to solve UVA 10315 http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1256
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* File: main.cpp | |
* Author: Corbin Hughes | |
* | |
* Created on DATE | |
*/ | |
#include <cstdlib> | |
#include <iostream> | |
#include <cstdio> | |
#include <string> | |
#include <sstream> | |
#include <set> | |
#include <map> | |
#include <fstream> | |
#include <vector> | |
#include <algorithm> | |
using namespace std; | |
int suitToNum(char suit) | |
{ | |
switch (suit) { | |
case 'C': | |
return 0; | |
case 'D': | |
return 1; | |
case 'H': | |
return 2; | |
case 'S': | |
return 3; | |
default: | |
return -1; | |
} | |
} | |
struct Card { | |
int val; | |
char suit; | |
int id; | |
Card(const int& val = -1, const char& suit = 'N') : val(val), suit(suit) | |
{ | |
id = 13 * suitToNum(suit) + (val-1); | |
} | |
Card& operator=(const Card& card) | |
{ | |
if (&card != this) { | |
val = card.val; | |
suit = card.suit; | |
id = card.id; | |
} | |
return *this; | |
} | |
Card(const Card& card) : val(card.val), suit(card.suit), id(card.id) | |
{ } | |
bool operator<(const Card& card) const | |
{ | |
return id < card.id; | |
} | |
bool operator>(const Card& card) const | |
{ | |
return id > card.id; | |
} | |
bool operator==(const Card& card) const | |
{ | |
return card.id == id; | |
} | |
bool operator!=(const Card& card) const | |
{ | |
return !operator==(card); | |
} | |
}; | |
class Hand | |
{ | |
private: | |
typedef vector<Card> card_container_t; | |
card_container_t cards; | |
mutable int rank; | |
int getHighCardRank(const map< int, set<int> >& countedValues) const | |
{ | |
//Hands which do not fit any higher category are ranked by the value of | |
//their highest card. If the highest cards have the same value, the hands are ranked | |
//by the next highest, and so on. | |
set<int>::const_iterator vit = countedValues.find(1)->second.begin(), | |
end = countedValues.find(1)->second.end(); | |
const int steps[] = {1, 14, 183, 2380, 30941}; | |
int rank = 0; | |
int idx = 0; | |
while (vit != end) { | |
rank += steps[idx] * (*vit); | |
++idx; | |
++vit; | |
} | |
return rank; | |
} | |
int calcRank() const | |
{ | |
// count -> suits | |
typedef map< int, set<char> > counted_suits_t; | |
counted_suits_t countedSuits; | |
// count -> values | |
typedef map< int, set<int> > counted_values_t; | |
counted_values_t countedValues; | |
// suit, s -> set of Cards with suit = s | |
typedef map< char, vector<Card> > grouped_suits_t; | |
grouped_suits_t groupedSuits; | |
// value, v -> set of Cards with value = v | |
typedef map< int, set<Card> > grouped_values_t; | |
grouped_values_t groupedValues; | |
for (card_container_t::const_iterator it = cards.begin(), end = cards.end(); it != end; ++it) { | |
const Card& c = *it; | |
groupedSuits[c.suit].push_back(c); | |
groupedValues[c.val].insert(c); | |
} | |
for (grouped_suits_t::const_iterator it = groupedSuits.begin(), end = groupedSuits.end(); it != end; ++it) { | |
countedSuits[it->second.size()].insert(it->first); | |
} | |
for (grouped_values_t::const_iterator it = groupedValues.begin(), end = groupedValues.end(); it != end; ++it) { | |
countedValues[it->second.size()].insert(it->first); | |
} | |
int minValue = groupedValues.begin()->first; | |
int maxValue = groupedValues.rbegin()->first; | |
bool flush = (countedSuits.find(5) != countedSuits.end()); | |
bool straight = true; | |
//TODO: this loop is unnecessary | |
set<int> vals; | |
for (card_container_t::const_iterator cit = cards.begin(), end = cards.end(); cit != end; ++cit) { | |
vals.insert(cit->val); | |
} | |
if (vals.size() == 5) { | |
for (set<int>::const_iterator sit = vals.begin(), end = vals.end(); sit != end;) { | |
int tmp = *sit; | |
++sit; | |
if (sit == end) { | |
break; | |
} | |
if (*sit - tmp != 1) { | |
straight = false; | |
break; | |
} | |
} | |
} else { | |
straight = false; | |
} | |
//Straight Flush: straight and a flush | |
//Ranked: Highest card in hand | |
if (straight && flush) { | |
//Straight Flush | |
return 800000000 + maxValue; | |
} | |
//Four of a Kind: 4 cards of the same value | |
//Ranked: value of one of the 4 cards | |
if (countedValues.find(4) != countedValues.end()) { | |
//Four of a kind | |
return 700000000 + *(countedValues.find(4)->second.begin()); | |
} | |
bool threeOfKind = (countedValues.find(3) != countedValues.end()); | |
int numPairs = 0; | |
counted_values_t::const_iterator pairsValues = countedValues.find(2); | |
if (pairsValues != countedValues.end()) { | |
for (set<int>::const_iterator siit = pairsValues->second.begin(), sie = pairsValues->second.end(); siit != sie; ++siit) { | |
numPairs += groupedValues[*siit].size() / 2; | |
} | |
} | |
//Full House: Three of a Kind and a Pair | |
//Ranked: value of one of the 3-kind cards | |
if (threeOfKind && numPairs == 1) { | |
return 600000000 + *(countedValues.find(3)->second.begin()); | |
} | |
//Flush: All five cards have the same suit | |
//Ranked: highest value of card in the hand | |
if (flush) { | |
return 500000000 + getHighCardRank(countedValues); | |
} | |
//Straight: Hand contains 5 cards with consecutive value | |
//Ranked: highest card in the hand | |
if (straight) { | |
return 400000000 + maxValue; | |
} | |
//Three of a Kind: three cards have the same value | |
//Ranked: Hands which | |
//both contain three of a kind are ranked by the value of the three cards. | |
if (threeOfKind) { | |
return 300000000 + *(countedValues.find(3)->second.begin()); | |
} | |
//Two Pairs: two pairs | |
//Ranked: Hands which both contain two pairs | |
//are ranked by the value of their highest pair. Hands with the same highest pair | |
//are ranked by the value of their other pair. If these values are the same the hands | |
//are ranked by the value of the remaining card. | |
if (numPairs == 2) { | |
set<int>::const_iterator cvi = countedValues.find(2)->second.begin(), | |
cve = countedValues.find(2)->second.end(); | |
int lowPair, highPair; | |
lowPair = *cvi; | |
if (++cvi == cve) { | |
highPair = lowPair; | |
} else { | |
highPair = *cve; | |
} | |
int rank = 200000000; | |
rank += 50000 * highPair; | |
rank += 1000 * lowPair; | |
rank += maxValue; | |
return rank; | |
} | |
//Pair: Two cards have the same value | |
//Ranked: Hands which both contain | |
//a pair are ranked by the value of the cards forming the pair. If these values are | |
//the same, the hands are ranked by the values of the cards not forming the pair, | |
//in decreasing order. | |
if (numPairs == 1) { | |
int rank = 100000000; | |
int pairVal = (*(countedValues.find(2)->second.begin())); | |
rank += 1000000 * pairVal; | |
set<int>::const_iterator vit = countedValues.find(1)->second.begin(), | |
end = countedValues.find(1)->second.end(); | |
rank += 50000 * (*vit); | |
++vit; | |
rank += 1000 * (*vit); | |
++vit; | |
rank += (*vit); | |
return rank; | |
} | |
return getHighCardRank(countedValues); | |
} | |
public: | |
Hand() : cards(), rank(-1) | |
{ } | |
Hand& operator=(const Hand& hand) | |
{ | |
if (&hand != this) { | |
cards = hand.cards; | |
rank = hand.rank; | |
} | |
return *this; | |
} | |
Hand(const Hand& hand) : cards(hand.cards), rank(hand.rank) | |
{ } | |
void addCard(const Card& card) | |
{ | |
cards.push_back(card); | |
} | |
size_t numCards() | |
{ | |
return cards.size(); | |
} | |
int getRank() const | |
{ | |
if (rank == -1) { | |
rank = calcRank(); | |
} | |
return rank; | |
} | |
bool operator<(const Hand& hand) const | |
{ | |
return hand.getRank() > getRank(); | |
} | |
bool operator>(const Hand& hand) const | |
{ | |
return hand.getRank() < getRank(); | |
} | |
bool operator==(const Hand& hand) const | |
{ | |
return hand.getRank() == getRank(); | |
} | |
bool operator!=(const Hand& hand) const | |
{ | |
//Could be optimized... | |
return !(operator==(hand)); | |
} | |
void printCards() const | |
{ | |
for (card_container_t::const_iterator i = cards.begin(), e = cards.end(); i != e; ++i) { | |
cout << "id = " << i->id << ", val = " << i->val << ", suit = " << i->suit << endl; | |
} | |
} | |
}; | |
istream& operator>>(istream& is, Card& card) | |
{ | |
char valC; | |
int val; | |
char suit; | |
if ((is >> valC) && (is >> suit)) { | |
if (valC == 'A') { | |
val = 14; | |
} else if (valC == 'K') { | |
val = 13; | |
} else if (valC == 'Q') { | |
val = 12; | |
} else if (valC == 'J') { | |
val = 11; | |
} else if(valC == 'T') { | |
val = 10; | |
} else { | |
val = valC - '0'; | |
} | |
card = Card(val, suit); | |
} else { | |
is.setstate(ios::failbit); | |
} | |
return is; | |
} | |
istream& operator>>(istream& is, Hand& hand) | |
{ | |
Card c; | |
hand = Hand(); | |
for (int i = 0; i < 5; ++i) { | |
if (is >> c) { | |
hand.addCard(c); | |
} else { | |
is.setstate(ios::failbit); | |
break; | |
} | |
} | |
if (hand.numCards() != 5 && is) { | |
cout << "Error reading cards" << endl; | |
hand.printCards(); | |
} | |
return is; | |
} | |
void consumeStream(istream& in) | |
{ | |
Hand white, black; | |
string line; | |
while (getline(in, line)) { | |
if (line.empty()) { | |
continue; | |
} | |
stringstream ss(line); | |
if (!(ss >> black)) { | |
break; | |
} | |
if (!(ss >> white)) { | |
break; | |
} | |
int brank = black.getRank(); | |
int wrank = white.getRank(); | |
//cout << "black rank " << brank << endl; | |
//cout << "white rank " << wrank << endl; | |
if (wrank == brank) { | |
cout << "Tie." << endl; | |
} else if (wrank > brank) { | |
cout << "White wins." << endl; | |
} else { | |
cout << "Black wins." << endl; | |
} | |
} | |
} | |
int main(int argc, char** argv) | |
{ | |
consumeStream(cin); | |
/*if (argc >= 2) { | |
fstream f(argv[1]); | |
consumeStream(f); | |
} else { | |
consumeStream(cin); | |
}*/ | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment