/*
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 combinations (with replacement) 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..

// FUCKING FIRST GOING TO GET IT WORKING WITH R=1 onwards.....
// THEN WILL TRY R=0

//included numbers  4,2,6 in X     
//N=6....


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

class Staircase 
{
    int N = 6;     // this can be changed by end user....
    
    Set <String> s = new HashSet<>();
    int[] X;
    int p;
    int total;
    int cycles=0;
    
     Random rand = new Random();
    
      
    // need to process whole thing until the set.size < combinations
    // there is no sense of X getting smaller since its with replacement....
    // need to only add the stringJoiner (converted into string) into the set if the total is equal to N
    //need
    
    
    public Staircase(long combinations, int[] X, int r)
    {
        this.X=X;
         
        System.out.println("Combinations: " + combinations);
        
        StringJoiner sj = new StringJoiner(",");
        
        int currentSetSize;
        int newSetSize;
        int count;
        
        
        do
        {
            total=0;
            sj = new StringJoiner(",");
            count=0;
            cycles=0;
            
        do
        {
           p= rand.nextInt(X.length);  // if length 3, it will give index numbers 0-2...
           
           int steps = X[p];
           System.out.println("random number is: " + steps);
           
           sj.add(Integer.toString(X[p]));
           total=total+steps;
           
           currentSetSize=s.size();
           
           System.out.println("current:" + currentSetSize);
           
           System.out.println("TOTAL: " + total);
           System.out.println("FUCKING VALUE OF N: " + N);
           System.out.println("FUCKING COUNT: " + count);
           System.out.println("FUCKING r: " + r);
           
           if (total==N && count<=r)
           {
           s.add(sj.toString());
           System.out.println("EVER HERE*****************");
           
           
               
           }
           count=count+1;
           
           //if (total>N || count>=r)
           //{
            //   break;
          // }
           
           newSetSize = s.size();
           System.out.println("new size: "+ newSetSize);
           
        
           if (newSetSize>currentSetSize)
           {
               System.out.println("This has been added into the set: " + sj.toString());
           }
        
        // issue with this loop... //currently there is no control of number selections from X....
        // This is denoted by value r..... However if this is enforced in below, it causes the do while to loop
        
        cycles++;
        
        }while (total<N);  
        
        //System.out.println("This is set size: " + s.size());
        System.out.println("Number of cycles: " + cycles + "\n");
        
        } while (s.size()<combinations);
          
        
        
    }
}


public class Combination
{
    public static void main(String[] args) 
    {
        System.out.println("Welcome to Online IDE!! Happy Coding :)");
        
        // this is going to be slight challenge...
        int originalNumber=0;   // for moment it is declared a 0 to keep next line content... This variable is based on the size of n in outer for loop...
        int n=originalNumber;   // this can stay here.... 
        int r;   // this does not need be in for loop
        
        int [] X = new int []{4,2,6};  //just to keep this loop flowing, I will complete exercise inline with 3 values in k..

        // Require a nested loop as follows and execution has to run separately

        //These are all scenarios
        //n=1 to  n< X.length()
        //r=1 to r<=n

        //need to understand that r can be greater than n in replacement.......
        //r is taken from n objects
        // in this example, r can get larger....

        Map <Integer, Long> m;  // this can stay outside loop since its not impacted by size of n and r
        
        //for (n=0; n<=X.length; n++)    
        
        n=X.length;
        
        // this should go from 1 to 3
        // this is fucking mistake! 
        // only meant to be fixed at value..... X.length()!!!!  objects.....
        // it's only in future if the X array grows, this will provide 
        
        //{
            System.out.println("VALUE N: " + n);
            System.out.println("Steps are: " + Arrays.toString(X));
            
            originalNumber=n;  // this will remain constant during a full iteration..
            
             m= new HashMap<>();  //new instance is required to start process again...
             
             for (r=3; r<=n+5; r++)  // for moment r is set 5 more than objects available.. This bit can be experimented later..
             {
                 System.out.println("\n***COMBINATIONS*** (WITH REPLACEMENT)");
                 System.out.println("C^R(n + r) = " + "(n+r-1)! / r!(n-1)!");
                 System.out.println("C^R(" + n+","+r+") = " + (n+r-1)+ "!" + " / " + r+"!"+"("+(n-1)+")!");
                 
                 
                 Staircase sc = new Staircase (Combinations (n,r,originalNumber, m), X, r);
                 //System.out.println(Combinations (n,r,originalNumber, m));
             }
       // }
        
    }

public static long Combinations (int n, int r, int originalNumber, Map factorialResults)
{
    long result=0;
    int denominator1; //denominator split two parts since there are two factorial calculations
    int denominator2; //denominator split two parts since there are two factorial calculations
    int Numerator=n+r-1; // Numerator
    int zero=0;
    long zeroFactorial = 1;

    // if no sample or objects, there are no outcomes...
    if (originalNumber==0 && r==0)
    {
        System.out.println("n and r can not both be equal to zero");
//System.exit(0);
return 0;
}
//this situation would occur if n is 0 only and r is any positive number accept 0 (if statement above)
//for instance (C^R (n,r)) = (0,3) 0+3-1 = 2 2<3
if (originalNumber==0 && originalNumber+r-1<r)
{
System.out.println("n+r-1 must be > or = to r");
//System.exit(0);
return 0;
}
if (Numerator>=1)

{

result = ((n+r-1)* (Combinations (n-1, r,originalNumber, factorialResults))); // this
//completes factorial for numerator
factorialResults.put(Numerator,result); //result stored in the Map
//factorialResults.put(n-1,result); //result stored in the Map
//System.out.println("getting result back out numerator: " + (Numerator) + " " + factorialResults.get(n+r-1));
if (n==originalNumber) // this will occur once
{
denominator1 = r;

denominator2 = originalNumber-1;

factorialResults.put(zero,zeroFactorial); //0! is equal to 1

if (factorialResults.containsKey(denominator1) &&
factorialResults.containsKey(denominator2))
{
long returnValue = result / ((long)factorialResults.get(denominator1) * (long)factorialResults.get(denominator2));
return returnValue;
}
}
return result;
}
return 1; // it will reach here only when condition not met (Numerator>=1)
}
}