// Arup Guha
// 8/29/2021
// Code to generate some test cases for the deck problem.

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

#define NUMCARDS 52
#define STRSIZE 2*NUMCARDS+1
#define NUMSWAP 1000

char deck[STRSIZE];

// Just put both of these in strings for easy access.
const char SUITS[5] = "CDHS";
const char KINDS[14] = "23456789TJQKA";

// Min and max case and printing.
void fillDeckInOrder();
void makeMinCase();
void print();

// For randomized cases.
void shuffle();
void swap(int a, int b);

// I didn't use this in my final data set.
void cutDeck();

// For last three cases.
void shuffleOutOfRange(int x, int y);
int in(int start, int end, int item) ;

int main(void) {

    printf("10\n");
    fillDeckInOrder();
    print();
    makeMinCase();
    print();

    for (int i=0; i<5; i++) {
        fillDeckInOrder();
        shuffle();
        print();
    }

    fillDeckInOrder();
    shuffleOutOfRange(14, 21);
    print();

    fillDeckInOrder();
    shuffleOutOfRange(36, 44);
    print();

    fillDeckInOrder();
    shuffleOutOfRange(13, 25);
    print();

    return 0;
}

void fillDeckInOrder() {

    // Loop through each combo of suit and kind, in order.
    for (int i=0; i<4; i++) {
        for (int j=0; j<13; j++) {

            // The indexing is a bit tricky, but 13*suit+kind gives us a 0 to 51 index
            // per card. Then, we multiply this by 2 because we have 2 characters per card.
            // Then we can add 0 or 1 to get the kind and suit indexes respectively.
            deck[2*(13*i+j)] = KINDS[j];
            deck[2*(13*i+j)+1] = SUITS[i];
        }
    }
    deck[STRSIZE-1] = '\0';
}

// Prints out the current deck. I just do it character by character.
void print() {
    for (int i=0; i<NUMCARDS; i++)
        printf("%c", deck[i]);
    printf("\n");
    for (int i=NUMCARDS; i<2*NUMCARDS; i++)
        printf("%c", deck[i]);
    printf("\n");
}

void makeMinCase() {

    // We will loop through the kinds but use i as an index to create a different kind.
    for (int i=0; i<13; i++) {

        // Suits will just go in order but in the inner loop.
        for (int j=0; j<4; j++) {

            // This formula ensures nothing is ever ascending!
            int kind = (3*i)%13;
            deck[2*(4*i+j)] = KINDS[kind];
            deck[2*(4*i+j)+1] = SUITS[j];
        }
    }
    deck[STRSIZE-1] = '\0';
}

void shuffle() {

    // Go through each swap.
    for (int i=0; i<NUMSWAP; i++) {
        int a = rand()%NUMCARDS;
        int b = rand()%NUMCARDS;

        // I just do both characters...
        swap(2*a, 2*b);
        swap(2*a+1, 2*b+1);
    }
}

// Leaves cards from locations [x,y] unchanged.
void shuffleOutOfRange(int x, int y) {

    // Go through each swap.
    for (int i=0; i<NUMSWAP; i++) {

        // Keep going until a and b are not in range.
        int a = 0, b = 0;
        while (1) {
            a = rand()%NUMCARDS;
            b = rand()%NUMCARDS;
            if (!in(x,y,a) && !in(x,y,b)) break;
        }

        // I just do both characters...
        swap(2*a, 2*b);
        swap(2*a+1, 2*b+1);
    }
}

// Returns 1 iff item is in between start and end.
int in(int start, int end, int item) {
    return item >= start && item <= end;
}

// Swaps locations a and b in deck.
void swap(int a, int b) {
    char tmp = deck[a];
    deck[a] = deck[b];
    deck[b] = tmp;
}

void cutDeck() {

    // Calculate cutting location.
    int loc = rand()%NUMCARDS;

    // This is the # of characters that are offset.
    int offset = 2*NUMCARDS - 2*loc;

    // Copy result here temporarily.
    char tmp[STRSIZE];

    // Copy the last portion of deck (AFTER cut pt) to front of tmp.
    for (int i=2*loc; i<STRSIZE-1; i++)
        tmp[i-2*loc] = deck[i];

    // Now, we're taking the rest of the cards and adding them to the end of tmp.
    for (int i=0; i<2*loc; i++)
        tmp[i+offset] = deck[i];

    // Copy back.
    for (int i=0; i<STRSIZE-1; i++)
        deck[i] = tmp[i];
}
