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


go =>
  Hands = [
            [[2,h], [7,h], [2,d], [3,c], [3,d]],  % two-pair
            [[2,h], [5,h], [7,d], [8,c], [9,s]],  % high-card
            [[a,h], [2,d], [3,c], [4,c], [5,d]],  % straight
            [[2,h], [3,h], [2,d], [3,c], [3,d]],  % full-house
            [[2,h], [7,h], [2,d], [3,c], [3,d]],  % two-pair
            [[2,h], [7,h], [7,d], [7,c], [7,s]],  % four-of-a-kind
            [[10,h],[j,h], [q,h], [k,h], [a,h]],  % straight-flush
            [[4,h], [4,s], [k,s], [5,d], [10,s]], % one-pair
            [[q,c], [10,c],[7,c], [6,c], [4,c]],  % flush
            [[q,c], [q,d], [q,s], [6,c], [4,c]],  % three-of-a-kind
 
            [[q,c], [10,c], [7,c], [7,c], [4,c]], % invalid (duplicates)
            [[q,c], [10,c], [7,c], [7,d]]         % invalid (too short)
 
          ],
  foreach(Hand in Hands) 
    print_hand(Hand),
    analyse(Hand, H),
    println(hand=H),
    nl
  end,
  nl.
 
 
% Print the hand
print_hand(Hand) =>
  println([ F.to_string() ++ S.to_string() : [F,S] in Hand]).
 
% Faces and suites
faces(Faces) => Faces = [a, 2, 3, 4, 5, 6, 7, 8, 9, 10, j, q, k].
faces_order1(Order1) => 
   Order1 = new_map([a=1, 2=2, 3=3, 4=4, 5=5, 6=6, 7=7, 8=8, 9=9, 10=10, j=11, q=12, k=13]).
faces_order2(Order2) => 
   Order2 = new_map([2=2, 3=3, 4=4, 5=5, 6=6, 7=7, 8=8, 9=9, 10=10, j=11, q=12, k=13, a=14]).
 
suites(Suites) => Suites = [h,d,c,s].
 
% Order of the hand
hand_order(HandOrder) => 
  HandOrder = [straight_flush,
               four_of_a_kind,
               full_house,
               flush,
               straight,
               three_of_a_kind,
               two_pair,
               one_pair,
               high_card,
               invalid].
 
 
% for the straight
in_order(List) =>
  foreach(I in 2..List.length)
    List[I] = List[I-1] + 1
  end.
 
 
% Some validity tests first
analyse(Hand,Value) ?=> 
  (
    Hand.remove_dups.length == 5,
    faces(Faces),
    foreach([F,_] in Hand) 
      member(F,Faces)
    end,
    suites(Suites),
    foreach([_,S] in Hand) 
      member(S,Suites)
    end,
    analyse1(Hand,Value)
   ;
    Value = invalid
  ).
 
% Identify the specific hands
 
% straight flush
analyse1(Hand,Value) ?=>
  permutation(Hand,Hand1),
  Hand1 = [ [_F1,S], [_F2,S], [_F3,S], [_F4,S], [_F5,S] ],
  (
    faces_order1(Order1),
    in_order([Order1.get(F) : [F,S1] in  Hand1])
    ; 
    faces_order2(Order2),
    in_order([Order2.get(F) : [F,S1] in  Hand1]),
    println("Royal Straight Flush!")
  ),
  Value=straight_flush.
 
% four of a kind
analyse1(Hand,Value) ?=> 
  faces(Faces),
  member(A,Faces),
  [1 : [F,_S] in Hand, F = A].length == 4,
  Value=four_of_a_kind.
 
% full house
analyse1(Hand,Value) ?=> 
  permutation(Hand,Hand1),
  Hand1 = [ [F1,_S1], [F1,_S2], [F2,_S3], [F2,_S4], [F2,_S5] ],
  Value = full_house.
 
% flush
analyse1(Hand,Value) ?=> 
  permutation(Hand,Hand1),
  Hand1 = [ [_,S], [_,S], [_,S], [_,S], [_,S] ],
  Value = flush.
 
% straight
analyse1(Hand,Value) ?=> 
  permutation(Hand,Hand1),
  (
    faces_order1(Order1),
    in_order([Order1.get(F) : [F,_S] in  Hand1])
    ; 
    faces_order2(Order2),
    in_order([Order2.get(F) : [F,_S] in  Hand1])
 
  ),
  Value = straight.
 
% three of a kind
analyse1(Hand,Value) ?=>
  faces(Faces),
  member(A,Faces),
  [1 : [F,_S] in Hand, F = A].length == 3,
  Value = three_of_a_kind.
 
% two pair
analyse1(Hand,Value) ?=> 
  permutation(Hand,Hand1),
  Hand1 = [ [F1,_S1], [F1,_S2], [F2,_S3], [F2,_S4], [_F3,_S5] ],
  Value = two_pair.
 
% one pair
analyse1(Hand,Value) ?=> 
  faces(Faces),
  member(A,Faces),
  [1 : [F,_S] in Hand, F = A].length == 2,
  Value = one_pair.
 
% high card
analyse1(_Hand,Value) => 
  Value = high_card.