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

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

// Function prototypes
void shuffle(int wDeck[][FACES]);
void deal(const int wDeck[][FACES], int hand[][2], const char *wFace[], const char *wSuit[]);
void evaluateHand(const int hand[][2]);
int hasPair(const int hand[][2]);
int hasTwoPairs(const int hand[][2]);
int hasThreeOfAKind(const int hand[][2]);
int hasFourOfAKind(const int hand[][2]);
int hasFlush(const int hand[][2]);
int hasStraight(const int hand[][2]);

int main(void) {
    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"
    };

    int deck[SUITS][FACES] = {0};
    int hand[HAND_SIZE][2]; // hand[i][0] = face index, hand[i][1] = suit index

    srand(time(NULL));
    shuffle(deck);
    deal(deck, hand, face, suit);
    evaluateHand(hand);

    return 0;
}

// Shuffle cards in deck
void shuffle(int wDeck[][FACES]) {
    for (int card = 1; card <= 52; ++card) {
        int row = rand() % SUITS;
        int column = rand() % FACES;
        while (wDeck[row][column] != 0) {
            row = rand() % SUITS;
            column = rand() % FACES;
        }
        wDeck[row][column] = card;
    }
}

// Deal 5 cards to the player
void deal(const int wDeck[][FACES], int hand[][2], const char *wFace[], const char *wSuit[]) {
    int cardCount = 0;
    printf("Player's Hand:\n");

    for (int c = 1; c <= HAND_SIZE; ++c) {
        for (int row = 0; row < SUITS; ++row) {
            for (int col = 0; col < FACES; ++col) {
                if (wDeck[row][col] == c) {
                    hand[cardCount][0] = col;
                    hand[cardCount][1] = row;
                    printf("  %s of %s\n", wFace[col], wSuit[row]);
                    cardCount++;
                }
            }
        }
    }
    printf("\n");
}

// Evaluate the poker hand using the required functions
void evaluateHand(const int hand[][2]) {
    printf("Hand Analysis:\n");
    
    if (hasFourOfAKind(hand)) {
        printf("- Contains Four of a Kind\n");
    }
    if (hasThreeOfAKind(hand)) {
        printf("- Contains Three of a Kind\n");
    }
    if (hasTwoPairs(hand)) {
        printf("- Contains Two Pairs\n");
    } else if (hasPair(hand)) {
        printf("- Contains a Pair\n");
    }
    if (hasFlush(hand)) {
        printf("- Contains a Flush\n");
    }
    if (hasStraight(hand)) {
        printf("- Contains a Straight\n");
    }

    if (!hasPair(hand) && !hasTwoPairs(hand) && !hasThreeOfAKind(hand) && 
        !hasFourOfAKind(hand) && !hasFlush(hand) && !hasStraight(hand)) {
        printf("- High Card hand (No special combinations)\n");
    }
}

// a) Determine whether the hand contains a pair
int hasPair(const int hand[][2]) {
    int faceCount[FACES] = {0};
    for (int i = 0; i < HAND_SIZE; ++i) {
        faceCount[hand[i][0]]++;
    }
    int pairs = 0;
    for (int i = 0; i < FACES; ++i) {
        if (faceCount[i] == 2) {
            pairs++;
        }
    }
    return (pairs == 1);
}

// b) Determine whether the hand contains two pairs
int hasTwoPairs(const int hand[][2]) {
    int faceCount[FACES] = {0};
    for (int i = 0; i < HAND_SIZE; ++i) {
        faceCount[hand[i][0]]++;
    }
    int pairs = 0;
    for (int i = 0; i < FACES; ++i) {
        if (faceCount[i] == 2) {
            pairs++;
        }
    }
    return (pairs == 2);
}

// c) Determine whether the hand contains three of a kind
int hasThreeOfAKind(const int hand[][2]) {
    int faceCount[FACES] = {0};
    for (int i = 0; i < HAND_SIZE; ++i) {
        faceCount[hand[i][0]]++;
    }
    for (int i = 0; i < FACES; ++i) {
        if (faceCount[i] == 3) {
            return 1;
        }
    }
    return 0;
}

// d) Determine whether the hand contains four of a kind
int hasFourOfAKind(const int hand[][2]) {
    int faceCount[FACES] = {0};
    for (int i = 0; i < HAND_SIZE; ++i) {
        faceCount[hand[i][0]]++;
    }
    for (int i = 0; i < FACES; ++i) {
        if (faceCount[i] == 4) {
            return 1;
        }
    }
    return 0;
}

// e) Determine whether the hand contains a flush (all cards same suit)
int hasFlush(const int hand[][2]) {
    int suitRef = hand[0][1];
    for (int i = 1; i < HAND_SIZE; ++i) {
        if (hand[i][1] != suitRef) {
            return 0;
        }
    }
    return 1;
}

// f) Determine whether the hand contains a straight (consecutive face values)
int hasStraight(const int hand[][2]) {
    int faces[HAND_SIZE];
    for (int i = 0; i < HAND_SIZE; ++i) {
        faces[i] = hand[i][0];
    }

    // Sort faces array using bubble sort
    for (int i = 0; i < HAND_SIZE - 1; ++i) {
        for (int j = 0; j < HAND_SIZE - i - 1; ++j) {
            if (faces[j] > faces[j + 1]) {
                int temp = faces[j];
                faces[j] = faces[j + 1];
                faces[j + 1] = temp;
            }
        }
    }

    // Check consecutive values
    for (int i = 0; i < HAND_SIZE - 1; ++i) {
        if (faces[i + 1] != faces[i] + 1) {
            return 0;
        }
    }
    return 1;
}
