第五回オフラインリアルタイムどう書くの回答例(C++)

お題はこちら http://qiita.com/items/5c10c132e1f78131563f

```cpp:

#include <string>
#include <vector>
#include <algorithm>
#include <iostream>
#include <fstream>
#include <sstream>
#include <iterator>
#include <functional>

//----------------------------------------------------------------------

const std::string ranks(" 3456789TJQKA2o");
const std::string suits("CDHJS");

int char2rank(int c)
{
    std::size_t r = ranks.find(c);
    if(r != std::string::npos)
    {
        return r;
    }
    else
    {
        return 0;
    }
}

char rank2char(std::size_t r)
{
    if((0 <= r) && (r < ranks.size()))
    {
        return ranks[r];
    }
    else
    {
        return '-';
    }
}

//----------------------------------------------------------------------

struct Card
{
    Card() : suit(0), rank(0) {}
    Card(int suit, int rank) : suit(suit), rank(char2rank(rank)) {}

    bool isValid() const { return (suits.find(suit) != std::string::npos) && (0 <= rank) && (rank < ranks.size()); }

    bool operator == (const Card& other) const { return (suit == other.suit) && (rank == other.rank); }
    bool operator != (const Card& other) const { return ! (*this == other); }
    bool operator <  (const Card& other) const { return  (suit < other.suit); }

    char        suit;
    std::size_t rank;
};

std::istream& operator >> (std::istream& in, Card& card)
{
    char s;
    char r;

    if((in >> s).good() && (suits.find(s) == std::string::npos))
    {
        in.putback(s);
        card = Card();
        return in;
    }

    if((in >> r).good() && (ranks.find(r) == std::string::npos))
    {
        in.putback(r);
        card = Card();
        return in;
    }

    if(in.good())
    {
        card = Card(s, r);
    }
    return in;
}

std::ostream& operator << (std::ostream& out, const Card& card)
{
    return out << card.suit << rank2char(card.rank);
}

//----------------------------------------------------------------------

typedef std::vector<Card> Cards;

bool operator == (const Cards& lhs, const Cards& rhs)
{
    return std::equal(lhs.begin(), lhs.end(), rhs.begin());
}

bool operator != (const Cards& lhs, const Cards& rhs)
{
    return ! (lhs == rhs);
}

std::size_t getRank(const Cards& cards)
{
    if(cards.empty())
    {
        return 0;
    }
    std::vector<Card>::const_iterator i = cards.begin();
    std::size_t rank = i->rank;
    ++i;
    for(; i != cards.end(); ++i)
    {
        if(rank == (ranks.size() - 1))
        {
            rank = i->rank;
        }
        else if((i->rank != (ranks.size() - 1)) && (i->rank != rank))
        {
            return 0;
        }
    }
    return rank;
}

std::istream& operator >> (std::istream& in, Cards& cards)
{
    for(;;)
    {
        Card card;
        in >> card;
        if( ! card.isValid())
        {
            break;
        }
        cards.push_back(card);
    }
    return in;
}

std::ostream& operator << (std::ostream& out, const Cards& cards)
{
    std::copy(cards.begin(), cards.end(), std::ostream_iterator<Card>(out, ""));
    return out;
}

//----------------------------------------------------------------------

struct Combination
{
    Combination(const Cards& cards, int n)
    {
        std::vector<int> v(n);
        combination(0, cards.size(), n, cards, 0, v);
    }

    void combination(int begin, int size, int n, const Cards& cards, int index, std::vector<int>& v)
    {
        if(n == 0)
        {
            v[index] = begin;
    
            Cards subset;
            for(std::vector<int>::iterator i = v.begin(); i != v.end(); ++i)
            {
                subset.push_back(cards[*i]);
            }
            values.push_back(subset);
            return;
        }
        for(int i = 0; i < size - n + 1; ++i)
        {
            v[index] = begin + i;
            combination(begin + i + 1, size - i - 1, n - 1, cards, index + 1, v);
        }
    }

    std::vector<Cards> values;
};

struct Invalid : std::unary_function<Cards, bool>
{
    Invalid(std::size_t rank) : rank(rank) {}

    bool operator () (const Cards& cards)
    {
        return getRank(cards) <= rank;
    }

    std::size_t rank;
};

void filter(int rank, std::vector<Cards>& piles)
{
    piles.erase(std::remove_if(piles.begin(), piles.end(), Invalid(rank)), piles.end());
}

//----------------------------------------------------------------------

std::string solve(const std::string& input)
{
    std::istringstream iss(input);
    Cards field;
    Cards hands;
    char  c;
    iss >> field >> c >> hands;
    if(hands.empty())
    {
        return "-";
    }

    Combination pile(hands, field.size());
    filter(getRank(field), pile.values);

    if(pile.values.empty())
    {
        return "-";
    }

    std::ostringstream oss;
    std::vector<Cards>::iterator itr = pile.values.begin();
    oss << *itr++;
    for(; itr < pile.values.end(); ++itr)
    {
        oss << ',' << *itr;
    }
    return oss.str();
}

//----------------------------------------------------------------------

struct Pattern
{
    Pattern(const std::string& s) : name(), input(), expected()
    {
        std::size_t d1 = s.find('¥t');
        std::size_t d2 = s.find('¥t', d1 + 1);
        if((d1 != std::string::npos) && (d2 != std::string::npos))
        {
            name     = s.substr(0, d1);
            input    = s.substr(d1 + 1, d2 - d1 - 1);
            expected = s.substr(d2 + 1);
        }
    }

    std::string name;
    std::string input;
    std::string expected;
};

std::vector<std::string> str2VectorOfCards(const std::string& s)
{
    std::vector<std::string> result;
    if(s == "-")
    {
        return result;
    }

    std::istringstream iss(s);

    while(iss.good())
    {
        Cards cards;
        iss >> cards;
        std::sort(cards.begin(), cards.end());
        std::ostringstream oss;
        oss << cards;
        result.push_back(oss.str());
        char c;
        iss >> c;
    }

    std::sort(result.begin(), result.end());
    return result;
}

int main(int, char* [])
{
    std::ifstream patterns("patterns.tsv");
    int           count_cases    = 0;
    int           count_failures = 0;
    std::string   s;
    while(std::getline(patterns, s).good())
    {
        ++count_cases;
        Pattern     pattern(s);
        std::string actual = solve(pattern.input);
        std::vector<std::string> actuals   = str2VectorOfCards(actual);
        std::vector<std::string> expecteds = str2VectorOfCards(pattern.expected);

        if( ! std::equal(actuals.begin(), actuals.end(), expecteds.begin()))
        {
            ++count_failures;
            std::cout << "Failure in " << pattern.name << "¥n"
                      << "expected: ¥"" << pattern.expected << "¥"¥n"
                      << "  actual: ¥"" << actual << "¥"¥n";
        }
    }
    std::cout << "¥nCases: " << count_cases << "  Failures: " << count_failures << "¥n";

    return 0;
}
```