/* Exercise 7.12
   Card Shuffling and Dealing: Dealing Poker Hands
*/

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define SUITS 4
#define FACES 13
#define CARDS 52
#define HAND_SIZE 5

void shuffle(int deck[][FACES]);
void dealHand(int deck[][FACES],
              int hand[][2]);

int containsPair(int hand[][2]);
int containsTwoPairs(int hand[][2]);
int containsThreeOfKind(int hand[][2]);
int containsFourOfKind(int hand[][2]);
int containsFlush(int hand[][2]);
int containsStraight(int hand[][2]);

void printHand(int hand[][2],
               const char *face[],
               const char *suit[]);


int main(void)
{
    int deck[SUITS][FACES] = { 0 };

    int hand[HAND_SIZE][2];

    const char *suit[SUITS] =
    { "Hearts", "Diamonds", "Clubs", "Spades" };

    const char *face[FACES] =
    {
        "Ace", "Deuce", "Three", "Four", "Five",
        "Six", "Seven", "Eight", "Nine", "Ten",
        "Jack", "Queen", "King"
    };

    srand((unsigned int)time(NULL));

    shuffle(deck);
    dealHand(deck, hand);

    printf("\nYour poker hand is:\n");

    printHand(hand, face, suit);

    printf("\nHand results:\n");

    if (containsPair(hand))
    {
        printf("The hand contains a pair.\n");
    }
    else
    {
        printf("The hand does not contain a pair.\n");
    }

    if (containsTwoPairs(hand))
    {
        printf("The hand contains two pairs.\n");
    }
    else
    {
        printf("The hand does not contain two pairs.\n");
    }

    if (containsThreeOfKind(hand))
    {
        printf("The hand contains three of a kind.\n");
    }
    else
    {
        printf("The hand does not contain three of a kind.\n");
    }

    if (containsFourOfKind(hand))
    {
        printf("The hand contains four of a kind.\n");
    }
    else
    {
        printf("The hand does not contain four of a kind.\n");
    }

    if (containsFlush(hand))
    {
        printf("The hand contains a flush.\n");
    }
    else
    {
        printf("The hand does not contain a flush.\n");
    }

    if (containsStraight(hand))
    {
        printf("The hand contains a straight.\n");
    }
    else
    {
        printf("The hand does not contain a straight.\n");
    }

    return 0;
}


void shuffle(int deck[][FACES])
{
    for (int card = 1; card <= CARDS; ++card)
    {
        int row;
        int column;

        do
        {
            row = rand() % SUITS;
            column = rand() % FACES;
        }
        while (deck[row][column] != 0);

        deck[row][column] = card;
    }
}


void dealHand(int deck[][FACES],
              int hand[][2])
{
    int cardNumber = 1;
    int cardCount = 0;

    for (int row = 0; row < SUITS; ++row)
    {
        for (int column = 0; column < FACES; ++column)
        {
            if (deck[row][column] == cardNumber)
            {
                hand[cardCount][0] = row;
                hand[cardCount][1] = column;

                ++cardCount;
                ++cardNumber;

                if (cardCount == HAND_SIZE)
                {
                    return;
                }
            }
        }
    }
}


void printHand(int hand[][2],
               const char *face[],
               const char *suit[])
{
    for (int i = 0; i < HAND_SIZE; ++i)
    {
        printf("%s of %s\n",
               face[hand[i][1]],
               suit[hand[i][0]]);
    }
}


int containsPair(int hand[][2])
{
    for (int i = 0; i < HAND_SIZE; ++i)
    {
        for (int j = i + 1; j < HAND_SIZE; ++j)
        {
            if (hand[i][1] == hand[j][1])
            {
                return 1;
            }
        }
    }

    return 0;
}


int containsTwoPairs(int hand[][2])
{
    int pairs = 0;

    for (int i = 0; i < HAND_SIZE; ++i)
    {
        int alreadyCounted = 0;

        for (int k = 0; k < i; ++k)
        {
            if (hand[k][1] == hand[i][1])
            {
                alreadyCounted = 1;
            }
        }

        if (alreadyCounted == 1)
        {
            continue;
        }

        int count = 0;

        for (int j = 0; j < HAND_SIZE; ++j)
        {
            if (hand[i][1] == hand[j][1])
            {
                ++count;
            }
        }

        if (count == 2)
        {
            ++pairs;
        }
    }

    return pairs >= 2;
}


int containsThreeOfKind(int hand[][2])
{
    for (int i = 0; i < HAND_SIZE; ++i)
    {
        int count = 0;

        for (int j = 0; j < HAND_SIZE; ++j)
        {
            if (hand[i][1] == hand[j][1])
            {
                ++count;
            }
        }

        if (count == 3)
        {
            return 1;
        }
    }

    return 0;
}


int containsFourOfKind(int hand[][2])
{
    for (int i = 0; i < HAND_SIZE; ++i)
    {
        int count = 0;

        for (int j = 0; j < HAND_SIZE; ++j)
        {
            if (hand[i][1] == hand[j][1])
            {
                ++count;
            }
        }

        if (count == 4)
        {
            return 1;
        }
    }

    return 0;
}


int containsFlush(int hand[][2])
{
    for (int i = 1; i < HAND_SIZE; ++i)
    {
        if (hand[i][0] != hand[0][0])
        {
            return 0;
        }
    }

    return 1;
}


int containsStraight(int hand[][2])
{
    int values[FACES] = { 0 };

    for (int i = 0; i < HAND_SIZE; ++i)
    {
        values[hand[i][1]] = 1;
    }

    for (int start = 0; start <= FACES - HAND_SIZE; ++start)
    {
        int straight = 1;

        for (int i = 0; i < HAND_SIZE; ++i)
        {
            if (values[start + i] == 0)
            {
                straight = 0;
            }
        }

        if (straight == 1)
        {
            return 1;
        }
    }

    /*
       Special case:
       Ace, Two, Three, Four, Five
    */

    if (values[0] == 1 &&
        values[1] == 1 &&
        values[2] == 1 &&
        values[3] == 1 &&
        values[4] == 1)
    {
        return 1;
    }

    return 0;
}