Skip to content

Instantly share code, notes, and snippets.

@jchughes
Created December 10, 2013 21:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jchughes/b7ac71568b7ade09eb3a to your computer and use it in GitHub Desktop.
Save jchughes/b7ac71568b7ade09eb3a to your computer and use it in GitHub Desktop.
/*
* 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