#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <math.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <malloc.h>
#define MAX_DICE 6
#define DICE_SIDES 6
extern int errno;
unsigned int **permutations[MAX_DICE];
unsigned int **unique[MAX_DICE];


uint32_t Permutations(uint32_t dice, uint32_t sides){
	if(dice < 1)
		return 0;
	uint32_t num1;
	uint32_t num2;
	uint32_t num3;
	uint32_t num4;
	//uint32_t index = 0;
	//uint32_t cur_dice = 1;
	//uint32_t cur_dig = 0;

	//this will store the dice results, least significant digit first
	//uint32_t *dig_count = (uint32_t *)malloc( dice*sizeof(uint32_t) );
	//(void)memset((void *)dig_count, 1, dice*sizeof(uint32_t) );
	//sides^dice = permutations
	uint32_t perms = pow(sides, dice);
	//printf("perms: %u\n", perms);
	//sleep(2);
//	permutations[dice-1] = (uint32_t **)malloc( perms*sizeof(uint32_t *) );

	//(*permutations) = (uint32_t **)malloc( 10000 );
//	if(permutations[dice-1] == NULL) printf("Error: malloc(): %d\n", errno);
//	for(num1=0; num1<perms; num1++){
//		permutations[dice-1][num1] = (uint32_t *)malloc( dice*sizeof(uint32_t) );
//		if(permutations[dice-1][num1] == NULL)
//			printf("Error: malloc(): %d\n", errno);
		//printf("%d\n", num1);
//	}
//printf("here 1\n");
    //412/6 = 68 remainder 4...  so the base 6 number is XXX4
    //68/6  = 11 remainder 2...  so the base 6 number is XX24
    //11/6  =  1 remainder 5...  so the base 6 number is X524
    //1/6   =  0 remainder 1...  so the base 6 number is 1524
	//Just count and convert base 10 to base sides (6)
	//for(num1=0; num1<perms; num1++){
	//	for(num2=0; num2<dice; num2++){
	//		(*permutations)[num1][num2] = 1;
	//	}
	//}
	for(num1=0; num1<perms; num1++){
		num3 = num1;
		for(num2=0; num2<dice; num2++){
			//num4 = num3/sides;
			num4 = num3 % sides;
			num3 /= sides;
			permutations[dice-1][num1][num2] = num4+1;
		}
	}
//printf("here 2\n");
	//free(dig_count);
	return perms;
}


uint32_t Unique(uint32_t dice, uint32_t sides){
	if(sides < 2)
		return 1;
	uint32_t num1, num2, num3, num4;
	uint32_t factorial = 1;
	uint32_t unique_count  = 1;
	for(num1 = 1; num1<sides; num1++){
		factorial *= num1*1;
	}
	for(num1 = 1; num1<sides; num1++){
		unique_count *= (dice+num1);
	}
	unique_count /= factorial;

	//printf("fact: %u uc: %u\n", factorial, unique_count);
	//uint32_t unique = (dice+5)*(dice+4)*(dice+3)*(dice+2)*(dice+1) / factorial;

	unique[dice-1] = (unsigned int **)malloc( unique_count*sizeof(unsigned int *) );
	if(unique[dice-1] == NULL) printf("Error: malloc(): %d\n", errno);
	for(num1 = 0; num1<unique_count; num1++){
		unique[dice-1][num1] = (unsigned int *)malloc(dice*sizeof(unsigned int) );
		if(unique[dice-1][num1] == NULL) printf("Error: malloc(): %d\n", errno);
	}
	uint32_t perms = pow(sides, dice);
	uint32_t match_found = 0;
	uint32_t unique_members = 0;
	size_t dig_c_size = sides*sizeof(unsigned int);
	unsigned int *dig_count1 = (unsigned int *)malloc( dig_c_size );
	unsigned int *dig_count2 = (unsigned int *)malloc( dig_c_size );
	(void)memset((void *)dig_count1, '\0', dig_c_size );
	(void)memset((void *)dig_count2, '\0', dig_c_size );
	//place first combination in unique array
	for(num1 = 0; num1<dice; num1++){
		unique[dice-1][0][num1] = permutations[dice-1][0][num1];
	}
	unique_members++;

	for(num1 = 0; num1<perms; num1++){
		match_found = 0;
		(void)memset((void *)dig_count1, '\0', dig_c_size );
		for(num2=0; num2<dice; num2++){
			num3 = permutations[dice-1][num1][num2];
			dig_count1[num3]++;
		}
		for(num2=0; num2<unique_members; num2++){
			(void)memset((void *)dig_count2, '\0', dig_c_size );
			for(num3=0; num3<dice; num3++){
				num4 = unique[dice-1][num2][num3];
				dig_count2[num4]++;
			}
			if(memcmp( (const void *)dig_count1, (const void *)dig_count2, dig_c_size) == 0){
				match_found = 1;
				break;
			}
		}
		if(match_found == 0){
			for(num2=0; num2<dice; num2++){
				unique[dice-1][unique_members][num2] = permutations[dice-1][num1][num2];
			}
			unique_members++;
		}
	}

	//free(dig_count1);
	//free(dig_count2);
	return unique_count;
}


int main(int argc, char **argv){
	uint32_t num1;
	uint32_t num2;
	//uint32_t index = 0;
	//uint32_t permutations[36][2];
	//uint32_t **permutations[6];
	//uint32_t **unique[6];
	uint32_t unique_count[MAX_DICE];
	//uint32_t max_dice = 6;
	//uint32_t sides = 6;
	uint32_t perms[MAX_DICE];
	uint32_t permu_tmp;
	//uint32_t unique[36][2];
	//uint32_t unique_count = 0;
	//int match_found = 0;

	//printf("permutations:\n");

/*
	for(num1=1; num1<7; num1++){
		for(num2=1; num2<7; num2++){
			//index++;
			//index = (num1-1) * (num2-1);
			permutations[index][0] = num1;
			permutations[index][1] = num2;
			printf("%u %u\n", num1, num2);
			index++;
		}
	}
*/
	printf("Dice:\n");
	for(num1=0; num1<MAX_DICE; num1++){
		printf("%u\n", num1+1);
		permu_tmp = pow(DICE_SIDES, num1+1);
		permutations[num1] = malloc( permu_tmp*sizeof(unsigned int *) );
		if(permutations[num1] == NULL) 
			printf("Error: malloc(): %d\n", errno);
		for(num2=0; num2<permu_tmp; num2++){
			permutations[num1][num2] = malloc( (num1+1)*sizeof(unsigned int) );
			if(permutations[num1][num2] == NULL)
				printf("Error: malloc(): %d\n", errno);
		}
	}
	for(num1=0; num1<MAX_DICE; num1++){
		perms[num1] = Permutations(num1+1, DICE_SIDES);
		printf("\tPermutations: %u\n", perms[num1]);

		unique_count[num1] = Unique(num1+1, DICE_SIDES);
		printf("\tCombinations: %u\n", unique_count[num1]);

		//for(num2=0; num2<perms; num2++){
		//	free(permutations[num2]);
		//}
		//free(permutations);
	}
/*
	for(num1=0; num1<perms; num1++){
		for(num2=0; num2<dice; num2++){
			printf("%u ", permutations[num1][num2]);
		}
		printf("\n");
	}
	//place first permuation in unique array
	unique[0][0] = permutations[0][0];
	unique[0][1] = permutations[0][1];
	unique_count++;

	printf("unique:\n");
	for(num1=0; num1<36; num1++){
		match_found = 0;
		for(num2=0; num2<unique_count; num2++){
			if(permutations[num1][0] == unique[num2][0]){
				if(permutations[num1][1] == unique[num2][1]){
					match_found = 1;
					break;
				}
			}
			if(permutations[num1][0] == unique[num2][1]){
				if(permutations[num1][1] == unique[num2][0]){
					match_found = 1;
					break;
				}
			}
		}
		if(match_found == 0){
			unique[unique_count][0] = permutations[num1][0];
			unique[unique_count][1] = permutations[num1][1];
			unique_count++;
		}
	}

	//print results
	for(num2=0; num2<unique_count; num2++){
		printf("%u. %u %u\n", num2, unique[num2][0], unique[num2][1]); 
	}
*/

//	for(num1=0; num1<perms; num1++){
//		free(permutations[num1]);
//	}
//	free(permutations);


	for(num1=0; num1<MAX_DICE; num1++){
		for(num2=0; num2<unique_count[num1]; num2++){
			free(unique[num1][num2]);
		}
		free(unique[num1]);
		for(num2=0; num2<perms[num1]; num2++){
			free(permutations[num1][num2]);
		}
		free(permutations[num1]);
	}
	return 0;
}