#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 getCard(int deck[][FACES],
             int cardNumber,
             int card[]);

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

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]);

int handValue(int hand[][2]);

void playerDraw(int deck[][FACES],
                int hand[][2],
                int *nextCard);

void dealerDraw(int deck[][FACES],
                int hand[][2],
                int *nextCard);


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

    int playerHand[HAND_SIZE][2];
    int dealerHand[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);

    for (int i = 0; i < HAND_SIZE; ++i)
    {
        getCard(deck, i + 1, playerHand[i]);
    }

    for (int i = 0; i < HAND_SIZE; ++i)
    {
        getCard(deck,
                HAND_SIZE + i + 1,
                dealerHand[i]);
    }

    int nextCard = 11;

    printf("Your hand before drawing:\n");
    printHand(playerHand, face, suit);

    playerDraw(deck, playerHand, &nextCard);

    printf("\nYour hand after drawing:\n");
    printHand(playerHand, face, suit);

    dealerDraw(deck, dealerHand, &nextCard);

    printf("\nDealer hand:\n");
    printHand(dealerHand, face, suit);

    printf("\nYour hand value = %d\n",
           handValue(playerHand));

    printf("Dealer hand value = %d\n",
           handValue(dealerHand));

    if (handValue(playerHand) > handValue(dealerHand))
    {
        printf("\nYou win.\n");
    }
    else if (handValue(dealerHand) > handValue(playerHand))
    {
        printf("\nDealer wins.\n");
    }
    else
    {
        printf("\nThe game is tied.\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 getCard(int deck[][FACES],
             int cardNumber,
             int card[])
{
    for (int row = 0; row < SUITS; ++row)
    {
        for (int column = 0; column < FACES; ++column)
        {
            if (deck[row][column] == cardNumber)
            {
                card[0] = row;
                card[1] = column;

                return;
            }
        }
    }
}


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


void playerDraw(int deck[][FACES],
                int hand[][2],
                int *nextCard)
{
    int choice;

    printf("\nHow many cards do you want to replace? ");
    scanf("%d", &choice);

    if (choice < 0)
    {
        choice = 0;
    }

    if (choice > HAND_SIZE)
    {
        choice = HAND_SIZE;
    }

    for (int i = 0; i < choice; ++i)
    {
        int cardNumber;

        printf("Enter the number of the card to replace: ");
        scanf("%d", &cardNumber);

        if (cardNumber >= 1 && cardNumber <= HAND_SIZE)
        {
            getCard(deck, *nextCard, hand[cardNumber - 1]);

            ++(*nextCard);
        }
        else
        {
            printf("Invalid card number.\n");
            --i;
        }
    }
}


void dealerDraw(int deck[][FACES],
                int hand[][2],
                int *nextCard)
{
    int keep[HAND_SIZE] = { 0 };

    if (containsFourOfKind(hand))
    {
        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)
            {
                keep[i] = 1;
            }
        }
    }
    else if (containsThreeOfKind(hand))
    {
        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)
            {
                keep[i] = 1;
            }
        }
    }
    else if (containsTwoPairs(hand))
    {
        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 == 2)
            {
                keep[i] = 1;
            }
        }
    }
    else if (containsPair(hand))
    {
        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 == 2)
            {
                keep[i] = 1;
            }
        }
    }

    for (int i = 0; i < HAND_SIZE; ++i)
    {
        if (keep[i] == 0)
        {
            getCard(deck, *nextCard, hand[i]);

            ++(*nextCard);
        }
    }
}


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 count = 0;

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

        if (count == 2)
        {
            int alreadyCounted = 0;

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

            if (alreadyCounted == 0)
            {
                ++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 <= 8; ++start)
    {
        int straight = 1;

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

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

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

    return 0;
}


int handValue(int hand[][2])
{
    if (containsFourOfKind(hand))
    {
        return 6;
    }

    if (containsFlush(hand) &&
        containsStraight(hand))
    {
        return 5;
    }

    if (containsThreeOfKind(hand) &&
        containsPair(hand))
    {
        return 4;
    }

    if (containsFlush(hand) ||
        containsStraight(hand))
    {
        return 3;
    }

    if (containsThreeOfKind(hand))
    {
        return 2;
    }

    if (containsTwoPairs(hand))
    {
        return 1;
    }

    if (containsPair(hand))
    {
        return 0;
    }

    return -1;
}