Task

Create a program to parse a single five card poker hand and rank it according to this list of poker hands.



A poker hand is specified as a space separated list of five playing cards.

Each input card has two characters indicating face and suit.



Example

2d       (two of diamonds).


Faces are:    a, 2, 3, 4, 5, 6, 7, 8, 9, 10, j, q, k

Suits are:    h (hearts),   d (diamonds),   c (clubs),   and   s (spades),   or

alternatively,   the unicode card-suit characters:     ♥ ♦ ♣ ♠ 



Duplicate cards are illegal.

The program should analyze a single hand and produce one of the following outputs:

 straight-flush
 four-of-a-kind
 full-house
 flush
 straight
 three-of-a-kind
 two-pair
 one-pair
 high-card
 invalid



Examples

   2♥ 2♦ 2♣ k♣ q♦:   three-of-a-kind
   2♥ 5♥ 7♦ 8♣ 9♠:   high-card
   a♥ 2♦ 3♣ 4♣ 5♦:   straight
   2♥ 3♥ 2♦ 3♣ 3♦:   full-house
   2♥ 7♥ 2♦ 3♣ 3♦:   two-pair
   2♥ 7♥ 7♦ 7♣ 7♠:   four-of-a-kind 
   10♥ j♥ q♥ k♥ a♥:  straight-flush
   4♥ 4♠ k♠ 5♦ 10♠:  one-pair
   q♣ 10♣ 7♣ 6♣ q♣:  invalid

The programs output for the above examples should be displayed here on this page.



Extra credit

 use the playing card characters introduced with Unicode 6.0 (U+1F0A1 - U+1F0DE).
 allow two jokers
 use the symbol   joker
 duplicates would be allowed (for jokers only)
 five-of-a-kind would then be the highest hand


More extra credit examples

   joker  2♦  2♠  k♠  q♦:     three-of-a-kind
   joker  5♥  7♦  8♠  9♦:     straight
   joker  2♦  3♠  4♠  5♠:     straight
   joker  3♥  2♦  3♠  3♦:     four-of-a-kind
   joker  7♥  2♦  3♠  3♦:     three-of-a-kind
   joker  7♥  7♦  7♠  7♣:     five-of-a-kind
   joker  j♥  q♥  k♥  A♥:     straight-flush
   joker  4♣  k♣  5♦ 10♠:     one-pair
   joker  k♣  7♣  6♣  4♣:     flush
   joker  2♦  joker  4♠  5♠:  straight
   joker  Q♦  joker  A♠ 10♠:  straight
   joker  Q♦  joker  A♦ 10♦:  straight-flush
   joker  2♦  2♠  joker  q♦:  four-of-a-kind



Related tasks

 Playing cards
 Card shuffles
 Deal cards_for_FreeCell
 War Card_Game
 Go Fish


import std.stdio, std.string, std.algorithm, std.range;
 
string analyzeHand(in string inHand) pure /*nothrow @safe*/ {
    enum handLen = 5;
    static immutable face = "A23456789TJQK", suit = "SHCD";
    static immutable errorMessage = "invalid hand.";
 
    /*immutable*/ const hand = inHand.toUpper.split.sort().release;
    if (hand.length != handLen)
        return errorMessage;
    if (hand.uniq.walkLength != handLen)
        return errorMessage ~ " Duplicated cards.";
 
    ubyte[face.length] faceCount;
    ubyte[suit.length] suitCount;
    foreach (immutable card; hand) {
        if (card.length != 2)
            return errorMessage;
        immutable n = face.countUntil(card[0]);
        immutable l = suit.countUntil(card[1]);
        if (n < 0 || l < 0)
            return errorMessage;
        faceCount[n]++;
        suitCount[l]++;
    }
 
    return analyzeHandHelper(faceCount, suitCount);
}
 
private string analyzeHandHelper(const ref ubyte[13] faceCount,
                                 const ref ubyte[4] suitCount)
pure nothrow @safe @nogc {
    bool p1, p2, t, f, fl, st;
 
    foreach (immutable fc; faceCount)
        switch (fc) {
            case 2: (p1 ? p2 : p1) = true; break;
            case 3: t = true; break;
            case 4: f = true; break;
            default: // Ignore.
        }
 
    foreach (immutable sc; suitCount)
        if (sc == 5) {
            fl = true;
            break;
        }
 
    if (!p1 && !p2 && !t && !f) {
        uint s = 0;
        foreach (immutable fc; faceCount) {
            if (fc)
                s++;
            else
                s = 0;
            if (s == 5)
                break;
        }
 
        st = (s == 5) || (s == 4 && faceCount[0] && !faceCount[1]);
    }
 
    if (st && fl)      return "straight-flush";
    else if (f)        return "four-of-a-kind";
    else if (p1 && t)  return "full-house";
    else if (fl)       return "flush";
    else if (st)       return "straight";
    else if (t)        return "three-of-a-kind";
    else if (p1 && p2) return "two-pair";
    else if (p1)       return "one-pair";
    else               return "high-card";
}
 
void main() {
    // S = Spades, H = Hearts, C = Clubs, D = Diamonds.
    foreach (immutable hand; ["2H 2D 2S KS QD",
                              "2H 5H 7D 8S 9D",
                              "AH 2D 3S 4S 5S",
                              "2H 3H 2D 3S 3D",
                              "2H 7H 2D 3S 3D",
                              "2H 7H 7D 7S 7C",
                              "TH JH QH KH AH",
                              "4H 4C KC 5D TC",
                              "QC TC 7C 6C 4C"])
        writeln(hand, ": ", hand.analyzeHand);
}