// Arup Guha
// 9/23/2025
// Solution for CIS 3362 Homework #4 Question 1

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

unsigned long long applyPermSol(unsigned long long block, const int perm[]);
void printBits(unsigned long long x);
unsigned long long setBitsRnd();

const int IP[64] = {58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4, 62, 54, 46, 38, 30, 22, 14, 6, 64, 56, 48, 40, 32, 24, 16, 8,
                    57, 49, 41, 33, 25, 17, 9, 1, 59, 51, 43, 35, 27, 19, 11, 3, 61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7};

int main() {

    srand(time(0));

    // Put test cases here.
    unsigned long long x = setBitsRnd();
    printBits(x);
    unsigned long long y = applyPermSol(x, IP);
    printf("\n\n");
    printBits(y);
    return 0;
}

// Pre-condition: perm is an array of size 64 storing a permutation of the integers from 1 to 64, which refer to
//                bit numbers 0 through 63 in block.
// Post-condition: returns the result of applying perm to the 64 bits in block as an unsigned long long.
//                 For this implementation, the bits are labeled left to right so the most significant bit is bit 0,
//                 the second most significant bit is bit 1, ..., the least significant bit is bit 63.
//                 This is opposite of the usual (1<<i) positioning...
unsigned long long applyPermSol(unsigned long long block, const int perm[]) {

    unsigned long long res = 0;
    for (int i=63,j=0; i>=0; i--,j++) {
        int getPos = 64 - perm[i];
        if (block & (1llu<<getPos)) res |= (1llu<<j);
    }

    return res;
}

// Just so we can see the bits.
void printBits(unsigned long long x) {

    // Go from MSB to LSB.
    for (int i=63; i>=0; i--) {

        // Isolate bit with a bitwise and with a number with a single 1 bit.
        if (x&(1ll<<i)) printf("1");
        else printf("0");

        // So each byte is in a line.
        if (i%8 == 0) printf("\n");
    }
    printf("\n");
}

// Returns an unsigned long long with random bits.
unsigned long long setBitsRnd() {

    unsigned long long x = 0;

    // Go to each bit.
    for (int i=0; i<64; i++) {

        // Get a random number 0 or 1.
        int tmp = rand()%2;

        // If it's odd, turn this bit on.
        if (tmp)
            x |= (1ll<<i);
    }

    return x;
}
