Monday, October 29, 2012

UVA: 10315 Programming Challenges (Skiena & Revilla) Volume-2

UVA 10315 - Poker Hands

Background- This problem has another mathematics based algorithm where hands are ranked in a table and a unique score is generated based on the user hand. So at the end we just need to compare White and Black hands value to decide the winner. I am working on it and soon I will share.
     Meanwhile a simple, straight forward implementation could be like this. It is quick enough with timing 0.008 sec over UVA input data set.

C++ Implementation - 

#include <iostream>
#include <vector>
#include <string>
#include <sstream>
#include <algorithm>
using namespace std;
typedef pair<short, char> card;
typedef vector<card> hand;
typedef pair<short, short> bet;

enum {
    BLACK = 0,
    WHITE = 1,
    TIE = 2
};

struct compare {
    bool operator() (card i, card j) { return (i.first > j.first);}
} cmp;


stringstream oss(stringstream::in | stringstream::out);
string output[] = {"Black wins.","White wins.","Tie."};

void read_hand(hand& h) {
    for(short i =0; i < 5; i++) {
        char rank, temp[2];
        oss >> temp[0] >> temp[1];
        rank = temp[0];
        card c;
        if(temp[1] == 'H' || temp[1] == 'D' || temp[1] == 'C' || temp[1] == 'S')
            c.second = temp[1];
        else 
            continue;
        if(rank >= '0' && rank <= '9')
            c.first = rank-48;
        else if(rank == 'T')
            c.first = 10;
        else if(rank == 'J')
            c.first = 11;
        else if(rank == 'Q')
            c.first = 12;
        else if(rank == 'K')
            c.first = 13;
        else if(rank == 'A')
            c.first = 14;
        else
            continue;
        h.push_back(c);    
    }
}
void print_hand(const hand& b, const hand& w) {
    hand::const_iterator it = b.begin();
    while(it != b.end()) {
        cout << it->first << it->second << " ";
        it++;
    }
    it = w.begin();
    while(it != w.end()) {
        cout << it->first << it->second << " ";
        it++;
    }
    cout << endl;
}
//1
bool high(hand& h, bet& b) {
    b = bet(1, h.begin()->first);
    return true;
}

//2:2, 3:2.2, 4:3, 7:3.2, 8:4
bool same_rank(hand& h, bet& b) {
    pair<short, short> rank1(0,0);
    pair<short, short> rank2(0,0);
    hand::iterator it = h.begin();
    rank1.first = it->first;
    rank1.second++;
    it++;
    while(it != h.end()) {
        if(it->first == rank1.first)
            rank1.second++;
        else {
            if( rank1.second < 2) {
                rank1.first = it->first;
                rank2.second = 1;
            } else {
                if(rank2.first == it->first) {
                    rank2.second++;
                } else if(rank2.first == 0){
                    rank2.first = it->first;
                    rank2.second = 1;
                } else if (rank2.second < 2) {
                    rank2.first = it->first;
                    rank2.second = 1;
                }
            }
        }
        it++;
    }
    if((rank1.second == rank2.second) && (rank1.second == 2)) {
        b.first = 3    ;
        b.second = rank1.first;
        return true;
    } else {
        //swap 
        if(rank1.second < rank2.second) {
            pair<short, short> temp(0,0);
            temp = rank1;
            rank1 = rank2;
            rank2 = temp;
        }
        if(rank1.second == 4) { 
            b.first = 8;
            b.second = rank1.first;
            return true;
        } else if(rank1.second == 3) {
            if(rank2.second == 2) {
                b.first = 7;
                b.second = rank1.first;
            } else {
                b.first = 4;
                b.second = rank1.first;
            }    
            return true;
        } else if(rank1.second == 2) {
            b.first = 2;
            b.second = rank1.first;
            return true;
        }
    }
    return false;
}

//5, 9
bool straight(hand& h, bet& b, bool fls=false) {
    for(short i =1; i < 5; i++) {
        if(h[0].first-i != h[i].first)
            return false;
    }
    if(fls == true) 
        b.first = 9;
    else
        b.first = 5;
    b.second = h[0].first;
    return true;
}

//6
bool flush(hand& h, bet& b) {
    hand::iterator it = h.begin();
    char color = it->second;
    it++;
    while(it != h.end()) {
        if(it->second != color)
            return false;
        it++;    
    }
    b.first = 6;
    b.second = h.begin()->first;
    return true;
}

bet get_bet(hand& h) {
    bet b;
    sort(h.begin(), h.end(), cmp);
    if(flush(h, b) == true) {
        straight(h, b, true);
        return b;
    } else if(straight(h, b) == true)
        return b;
    else if (same_rank(h, b) == true)
        return b;
    else {
        high(h, b);
        return b;
    }
}

short Show(hand& black, hand& white) {
    bet b_bet = get_bet(black);
    bet w_bet = get_bet(white);
    if(b_bet.first == w_bet.first) {
        if(b_bet.second == w_bet.second) {
            while(black.empty() == false) { 
                if(black.front().first == white.front().first) {
                    black.erase(black.begin());        
                    white.erase(white.begin());
                } else {
                    if(black.front().first > white.front().first) 
                        return BLACK;
                    else
                        return WHITE;
                }
            }
            return TIE;
        } else if(b_bet.second > w_bet.second) {
            return BLACK;
        } else {
            return WHITE;
        }
    } else if(b_bet.first > w_bet.first) {
        return BLACK;
    } else {
        return WHITE;
    }
}

int main() {
    hand black;
    hand white;
    while(cin.eof() == false) {
        string line;
        oss.str("");
        cin >> ws;
        getline(cin, line);
        if(line.size() < 29)
            continue;
        oss << line;
        black.clear();
        white.clear();
        read_hand(black);
        read_hand(white);
        if((black.size() == white.size()) && (black.size() == 5)) {
            //print_hand(black, white);
            short result = Show(black, white);
            cout << output[result] << endl;
        }
    }
    return 0;    
}

     
After thoughts - 
1. There is plenty scope to optimize this.
2. There is another way to encode the cards in a way to reveal the rank quickly. I am using the same in different poker and Yahtzee problem. 
3. I didn't change this because I want to replace this with math based ranking algorithm.

No comments:

Post a Comment