/*
Online Java - IDE, Code Editor, Compiler

Online Java is a quick and easy tool that helps you to build, compile, test your programs online.
*/

// This has been created to ensure I can utilize any random functions more efficiently.
// It is a creation of the NcR    combinations calculator.
// It has used techniques I learnt including recursion and also memoization to speed up execution.
// I will incorporate this into Java applications I created previously..

import java.math.*;
import java.util.*;


class largestNumber
{
    long combinations;
    int count;
    String temp;
    
    Set <String> s = new HashSet <>();
    
    //List <Integer> lst = new ArrayList<>(Arrays.asList(10,7,76,415));
    
    List <Integer> lst = new ArrayList<>(Arrays.asList(1,2,3,4));
    
    List <Integer> copy = new ArrayList<>(lst);  //keeps a copy
    
    //copy.addAll(lst);
    
    public largestNumber(long combinations)
    {
        
        this.combinations=combinations;
        int randomNumber;
        int numberArray;
        
        Random rand = new Random();
        
        System.out.println("Combinations: " + combinations);
       
        
        do
        {
            System.out.println("\nset size: " + s.size());
            lst = new ArrayList<>(copy);
            //it needs to put list back to how it was!!!
            
            //System.out.println("To test if both copied: " + lst.get(0));
            
            temp="";
            
            //for (int i=0; i<lst.size();i++)
            //{
            
            do
            {
                System.out.println("Size of list: " + lst.size());
                
                randomNumber = rand.nextInt(lst.size());
                System.out.println("random number: " + (randomNumber));
                
                numberArray = lst.get(randomNumber);   //gets number from the list
                System.out.println("This is number in list: " + numberArray);
                
                temp =  temp + Integer.toString(numberArray);    // this will produce 0-3
                
                
                lst.remove(randomNumber);
                
                //System.out.println("value of i: " + i + "\n");
                
            } while (!lst.isEmpty());
            
            
            s.add(temp);
            //System.out.println(s.get());
        
        count++;
        System.out.println("count should be 1: " + count);
            
            
        } while (s.size()<=23);
        
        
        System.out.println("Number cycles: " + count);
        
        checkMaximum();
        
    }
    
    public int checkMaximum()
    {
        Iterator it = s.iterator();
        
        while(it.hasNext())
        {
            
        }
        
        return 1;
    }
}


public class Combination
{
    public static void main(String[] args) {
        System.out.println("Welcome to Online IDE!! Happy Coding :)");
        
        int originalNumber=4;
        int n=originalNumber;
        int r =4;
        Map <Integer, Long> m = new HashMap<>();
        System.out.println("***COMBINATIONS***");
        System.out.println("P(" + n+","+r+") = " + n+"!" + " / " + "("+r+"!"+"("+n+"-"+r+")!)");
        
        largestNumber ln = new largestNumber(Combinations (n,r,originalNumber, m));
        
    }
    
    public static long Combinations (int n,  int r, int originalNumber, Map factorialResults)
    {
        
        // n are objects
        // r is sample
       
       /*
       ***CALCULATION***
        P(n,r) =   n! /  (r!(n−r)!)
        
        */
        
        long result=0;
        int denominator1;
        int denominator2;
        
        if (n>=1)
        {
            // EXAMPLE
            
            // P (5,6)   =   6* 5* 4 * 3 * 2 * 1   /   6! (6-5)!     =    720 / (5! * 1!) =  120 / 5*4*3*2*1  * 1  = 720 / 120 = 6
        
        result = (n* (Combinations (n-1, r,originalNumber, factorialResults)));   // this completes factorial for numerator
        
        factorialResults.put(n,result);   //result stored in the Map
        //System.out.println("getting result back out: " + factorialResults.get(n));
        
        
        if (n==originalNumber)   // this will occur once
        {
            
            denominator1 = originalNumber-r;        // originalNumber required since n has reduced as part of the recursive calls
           
            denominator2 = r;                       // r sample size has not changed
           
            
        // this is using the Java Memoization technique to ensure the factorial outcome is not calculated again, to save program cycles.
        // since the returns are done in reverse order.... n = 1 is processed first and n=6 last... Hence in practice
        // there will be entry in Map for all factorials, ready for the denominator..
        
        
            if (factorialResults.containsKey(denominator1) && factorialResults.containsKey(denominator2))
            
            {
                //System.out.println("here");
                //System.out.println("This is exact value of factorial  " + (denominator1) + " : " +  factorialResults.get(denominator1));
                //System.out.println("This is exact value of factorial  " + (denominator2) + " : " +  factorialResults.get(denominator2));
               
                return result / ((long) factorialResults.get(denominator1) * (long)factorialResults.get(denominator2));
            }
           
        }
           
            return result;
            
        }
          return 1;    // it should not reach here  
        }
        
    }