/*
 * File:   main.cpp
 * Author: Joe Churchwell
 *
 * Created on November 7, 2013, 10:17 AM
 * 
 * This code is created to calculate and print out all possible combinations of
 * lottery numbers. I could not believe that I found a web site that charges
 * for a set of files listing all of these numbers so I decided to create this
 * myself.  
 * 
 * There are two methods used for all the number sequences of n choose k.  
 * The first method uses recursion and the second uses a sequential solution.  
 * The recursive solution is more dynamic and can be expanded easier at the 
 * cost of iteration, and thus speed overhead. It can be seen that the actual
 * calculation of all possible number sequences is really fast but the output
 * to file or stdout is incredibly slow.
 * 
 * NOTES:
 * 1) To use the sequential solution comment out the USE_RECURSION define 
 *    statement
 * 2) To print out to file uncomment the PRINT_RESULTS define statement
 * 
 * 
 * 
 */

#include <cstdlib>
#include <cstdio>
#include <stdlib.h>

using namespace std;

// Comment this out to use the sequential solution
#define USE_RECURSION

// Comment this out to not output the results to a set of files
//#define PRINT_RESULTS

#define NON_MF_PROB 258890850

#define MAX_NUMBER 75
#define MIN_NUMBER  1
#define MAX_POWER_NUMBER 15
#define POOL_PLAYS 5

// Using Binomial Coefficient
#define PROBABILITY \
(MAX_POWER_NUMBER * fact(MAX_NUMBER,MAX_NUMBER-POOL_PLAYS)/fact(POOL_PLAYS, 0))

typedef unsigned int uInt32;

unsigned long long fact(int n, int stop);
void print_poss_recurse(uInt32 level, uInt32 last_number);
void print_poss(void);
char Create_File(uInt32 start, uInt32 end);

// Array to store all the numbers
char all_numbers[NON_MF_PROB][POOL_PLAYS+1];
char store_values[POOL_PLAYS+1];

unsigned long iterations = 0;

int main(int argc, char** argv) {
    
    uInt32 i;
    
    printf("Prob %u\n", PROBABILITY);
    
#ifdef USE_RECURSION
    print_poss_recurse(0,0); // This is the recursive solver
#else
    print_poss(); // This is the sequential solver
#endif
    
    printf("Iterations performed = %lu\n", iterations);
    
#ifdef PRINT_RESULTS
    for(i=0;i<NON_MF_PROB;i += NON_MF_PROB/37){
        Create_File(i, i + (NON_MF_PROB/37) - 1);
    }
#endif
    
    return 0;
}

// Factorial
unsigned long long fact(int n, int stop){
    int i;
    unsigned long long retVal = n;
    for(i=n-1; i>stop; i--) retVal *= i;
    return retVal;
}

void print_poss_recurse(uInt32 level, uInt32 last_number){
    uInt32 i, j;    
    if(level+1 > POOL_PLAYS){ // Exit condition (Power ball)
        for(i=1; i<=MAX_POWER_NUMBER; i++){
            store_values[level] = i;
            for(j=0;j<=level;j++) all_numbers[iterations][j] = store_values[j];
            iterations++;                       
        }        
        return;
    }
    for(i=(MAX_NUMBER-POOL_PLAYS+(level+1)); i>last_number; i--){  
        store_values[level] = i;
        print_poss_recurse(level+1, i);
    }        
}

void print_poss(void)
{
    uInt32 i, j, k, m, n, p;    
    for(i=(MAX_NUMBER-POOL_PLAYS+1); i>0; i--){
        for(j=(MAX_NUMBER-POOL_PLAYS+2); j>i; j--){
            for(k=(MAX_NUMBER-POOL_PLAYS+3); k>j; k--){
                for(m=(MAX_NUMBER-POOL_PLAYS+4); m>k; m--){
                    for(n=MAX_NUMBER;n>m; n--){
                        for(p=1; p<=MAX_POWER_NUMBER; p++){
                            all_numbers[iterations][0] = i;
                            all_numbers[iterations][1] = j;
                            all_numbers[iterations][2] = k;
                            all_numbers[iterations][3] = m;
                            all_numbers[iterations][4] = n;
                            all_numbers[iterations][5] = p;
                            iterations++;
                         //printf("%02d %02d %02d %02d %02d %02d\n",i,j,k,m,n,p);                         
                        }
                    } // END for n
                } // END for m
            } // END for k
        } // END for j
    }// END for i
}

// Output data to text file
char Create_File(uInt32 start, uInt32 end){
    
    FILE *fp;
    uInt32 i,j;
    
    // Get the file name from the start
    char str[14];
    sprintf(str, "%d.txt", start);
    
    // Open the file we want to output
    fp = fopen(str, "w");

    // Loop through all the number sets we want for this file
    for(i=start; i<=end;i++){
        // Loop through all the numbers for a given set
        for(j=0; j<=POOL_PLAYS; j++){
            fprintf(fp, "%i\t", all_numbers[i][j]);
        }
        // Make sure a new line is added after the sequence of numbers
        fprintf(fp, "\n");
    }
    
    // Make sure the file is closed
    fclose(fp);
    
    return 0;
    
}