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

//NOTE THE CODE HAS NOT BEEN ENHANCED TO SUPPORT BIGINTEGER FOR THE PERMUTATION CLASS
//HOWEVER IT IS POTENTIALLY NOT NECESSARY SINCE THE OUTER DO WHILE LOOP OF THE CODE
//REFERENCES 108883584818776183656945007213012309135068193536000
//SO IT FACILITATES THIS MANY BOARDS.... ASSUMING IDE CAN REACH THIS
//WE KNOW IF THE BOARDS ARE GENERATED AND FED INTO CHATGPT VALIDATOR, IT WILL VALIDATE BOARDS SUCCESSFULLY.
//SEE AREAS OF CODE WITH COMMENTS OPTION 2 AND OPTION 1


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

interface Fillable
{
    public void fill3x3();
    public void fill9x9(Map<BigInteger, int[][]> mp);
    public boolean checkUniqueRows(int [][] temp, int rowIndex);
    public boolean checkUniqueColumns(int[][] nineByNine, int colIndex);
    public boolean sudokuComplete(boolean a, boolean b);
    public void wipe9x9Board(int[][] formattedBoard, int[][] nineByNine);
    public void print9x9Board(String history);
    public int convertStringTo3x3(String permutations3x3, int getNumString);
    public void realTime9x9Fill(String history);
    public void display9x9();
}

class Sudoku implements Fillable
{
    BigInteger prevNumComplete9x9Boards=new BigInteger("0");
    boolean hasPerformedOnce=false;
    int minimum=362880;
    int maximum=0;

    StringJoiner permutationsSelected=new StringJoiner(",");
    int randomNumber;
    StringJoiner summary;
    StringJoiner summary1;
    int numAttempts;
    int numRetrieved3x3GridsIn9x9Grid;
    BigInteger numberPossibleBoards = new BigInteger("108883584818776183656945007213012309135068193536000");

    Set<String> permutationAllBoards = new HashSet();
    Map<BigInteger, int[][]> mp = new HashMap();

    int possibleNumbers[] = new int[]{1,2,3,4,5,6,7,8,9};

    List<Integer> lst = new ArrayList<Integer>();

    int formattedBoard[][] = new int [9][9];

    Map<BigInteger, int[][]> completedBoards = new HashMap<>();

    BigInteger numComplete9x9Boards = new BigInteger("1");

    StringJoiner sj1 = new StringJoiner(",");

    int [][] nineByNine = new int[][]
            {       {0,0,0,0,0,0,0,0,0},
                    {0,0,0,0,0,0,0,0,0},
                    {0,0,0,0,0,0,0,0,0},
                    {0,0,0,0,0,0,0,0,0},
                    {0,0,0,0,0,0,0,0,0},
                    {0,0,0,0,0,0,0,0,0},
                    {0,0,0,0,0,0,0,0,0},
                    {0,0,0,0,0,0,0,0,0},
                    {0,0,0,0,0,0,0,0,0}
            };

    int totalNumbersProcessed=1;
    long permutations;
    String Permutations3x3into9x9;

    int threeBythree[][] = new int[3][3];

    Set<String> s = new HashSet();
    Set<String> copyPermuations = new HashSet(s);

    StringJoiner sj;

    BigInteger currentSize = new BigInteger("0");
    BigInteger newSize = new BigInteger("0");

    List<Integer> copy = new ArrayList<>(lst);

    boolean endFirstRow3x3=false;
    Random rand = new Random();

    //unable to reach maximum stated online, this should suffice although
    //if the BigInteger code reaches as far as this, code will error due to exception.
    //simply disable the usage of completedBoardsLogs in all areas of code
    String[] completedBoardsLogs = new String[100000000];

    int count=0;
    int rowIndex=0;
    int colIndex=0;

    int randomNumber1to9List;

    boolean failedColumns;
    boolean failedRows;
    boolean sudokuSuccess;

    public void wipe9x9Board(int [][]formattedBoard, int nineByNine[][])
    {
        for (int q=0; q<nineByNine.length; q++)
        {
            for (int r=0; r<nineByNine[0].length; r++)
            {
                formattedBoard[q][r]=0;
                nineByNine[q][r]=0;
            }
        }
    }

    public Sudoku(long permutations, String  Permutations3x3into9x9)
    {
        this.permutations=permutations;
        this.Permutations3x3into9x9=Permutations3x3into9x9;

        fill3x3();
    }

    public int convertStringTo3x3(String permutations3x3, int getNum)
    {
        int temp;
        char num;
        String numString;

        num=permutations3x3.charAt(getNum);
        numString= String.valueOf(num);

        temp= Integer.parseInt(numString);
        return temp;
    }

    public void fill3x3()
    {
        int row=0;
        int col=0;
        int numbersProcessed;

        sj = new StringJoiner(",");

        System.out.println("There are : " + permutations + " permutations of arranging  3 x 3 grid" );
        System.out.println("There are : " + Permutations3x3into9x9 + " permutations of arranging  3 x 3 grid into 9 x 9:" + "P(362880,9)" );
        System.out.println("There are : 6,670,903,752,021,072,936,960" + " permutations of completing sudoku (taken from internet)");

        System.out.println("This code will attempt to explore but its impossible to expect much");
        System.out.println("It is used for foundation of experimentation but also it has made serious attempt to complete random process to make a grid");

        do
        {
            IntStream stream = Arrays.stream(possibleNumbers);
            stream.forEach(str -> lst.add(str));

            numbersProcessed=0;

            do
            {
                endFirstRow3x3=false;

                randomNumber = rand.nextInt(lst.size());

                randomNumber1to9List=lst.get(randomNumber);
                threeBythree[row][col]= randomNumber1to9List;

                sj.add(Integer.toString(randomNumber1to9List));
                lst.remove(randomNumber);

                if (col%2==0 && col!=0)
                {
                    row++;
                    col=0;
                    endFirstRow3x3 = true;
                }

                if (!endFirstRow3x3)
                {
                    col++;
                }

                numbersProcessed++;

            }while(!lst.isEmpty());

            currentSize = new BigInteger(String.valueOf(s.size()));

            s.add(sj.toString());

            newSize=new BigInteger(String.valueOf(s.size()));

            sj=new StringJoiner(" ");

            if (newSize.compareTo(currentSize)==1)
            {
                mp.put(newSize,threeBythree);
            }

            row=0;
            col=0;

        }while (newSize.compareTo(new BigInteger(String.valueOf(362880)))==-1);

        if(!hasPerformedOnce)
        {
            System.out.println("These are 3x3 permutations stored: " + s.size() +"\n");
        }


        //IF WANTING TO INPUT PERSONAL ENTRIES INTO THE PERMUTATIONS OR CLEAR ENTRIES
        //USEFUL TESTING

        /*
        if (!hasPerformedOnce)
        {
            s.clear();

            //We know this is a valid board configuration...
            //So I am going to extract these out into mini 3x3 grids inline with how my code processes information

                THIS IS A VALID BOARD FROM THE OUTPUTS
	            //123 789 456
	            //456 123 789
	            //789 456 123
	            //978 564 312
	            //312 897 645
	            //645 231 978
	            //231 645 897
	            //564 978 231
	            //897 312 564



            s.add("1,2,3,4,5,6,7,8,9");
            s.add("7,8,9,1,2,3,4,5,6");
            s.add("4,5,6,7,8,9,1,2,3");
            s.add("9,7,8,3,1,2,6,4,5");
            s.add("5,6,4,8,9,7,2,3,1");
            s.add("3,1,2,6,4,5,9,7,8");
            s.add("2,3,1,5,6,4,8,9,7");
            s.add("6,4,5,9,7,8,3,1,2");
            s.add("8,9,7,2,3,1,5,6,4");

            hasPerformedOnce=true;

            //System.out.println("JUST ONCE");
        }
        */


        /*
        //We know this translates as:
        1(0,0) 2(0,1) 3(0,2) 4(1,0) 5(1,1) 6(1,2) 7(2,0) 8(2,1) 9(2,2)
        4(0,3) 5(0,4) 6(0,5) 7(1,3) 8(1,4) 9(1,5) 1(2,3) 2(2,4) 3(2,5)
        7(0,6) 8(0,7) 9(0,8) 1(1,6) 2(1,7) 3(1,8) 4(2,6) 5(2,7) 6(2,8)

        2(3,0) 3(3,1) 1(3,2) 6(4,0) 4(4,1) 5(4,2) 9(5,0) 7(5,1) 8(5,2)
        5(3,3) 6(3,4) 4(3,5) 9(4,3) 7(4,4) 8(4,5) 3(5,3) 1(5,4) 2(5,5)
        8(3,6) 9(3,7) 7(3,8) 3(4,6) 1(4,7) 2(4,8) 6(5,6) 4(5,7) 5(5,8)

        3(6,0) 1(6,1) 2(6,2) 5(7,0) 6(7,1) 4(7,2) 8(8,0) 9(8,1) 7(8,2)

        6(6,3) 4(6,4) 5(6,5) 8(7,3) 9(7,4) 7(7,5) 2(8,3) 3(8,4) 1(8,5)
        9(6,6) 7(6,7) 8(6,8) 2(7,6) 3(7,7) 1(7,8) 5(8,6) 6(8,7) 4(8,8)

        //This would be search String to search for in the screen output
        1(0,0) 2(0,1) 3(0,2) 4(1,0) 5(1,1) 6(1,2) 7(2,0) 8(2,1) 9(2,2) 4(0,3) 5(0,4) 6(0,5) 7(1,3) 8(1,4) 9(1,5) 1(2,3) 2(2,4) 3(2,5) 7(0,6) 8(0,7) 9(0,8) 1(1,6) 2(1,7) 3(1,8) 4(2,6) 5(2,7) 6(2,8) 2(3,0) 3(3,1) 1(3,2) 6(4,0) 4(4,1) 5(4,2) 9(5,0) 7(5,1) 8(5,2) 5(3,3) 6(3,4) 4(3,5) 9(4,3) 7(4,4) 8(4,5) 3(5,3) 1(5,4) 2(5,5) 8(3,6) 9(3,7) 7(3,8) 3(4,6) 1(4,7) 2(4,8) 6(5,6) 4(5,7) 5(5,8) 3(6,0) 1(6,1) 2(6,2) 5(7,0) 6(7,1) 4(7,2) 8(8,0) 9(8,1) 7(8,2) 6(6,3) 4(6,4) 5(6,5) 8(7,3) 9(7,4) 7(7,5) 2(8,3) 3(8,4) 1(8,5) 9(6,6) 7(6,7) 8(6,8) 2(7,6) 3(7,7) 1(7,8) 5(8,6) 6(8,7) 4(8,8)
        */

        fill9x9(mp);
    }

    public void fill9x9(Map<BigInteger, int[][]> mp)
    {

        int temp[][]=new int[3][3];
        int successfulInputted3x3=0;

        Set <int[][]> st = new HashSet<>(mp.values());

        int rowCount=0;
        int colCount=0;

        int offset=0;
        int i=1;
        int numberOf3x3Processed=0;
        int m;
        String entry3x3="";

        boolean condition1=false;
        boolean condition2=false;
        boolean condition3=false;


        //I am now going to dismantle the below code and input blocks directly into String and forget random number.
        //And pull the grids out sequentually.
        //This is only technique to test the methods.

    /*   THIS IS A VALID BOARD FROM THE OUTPUTS
	123 789 456
	456 123 789
	789 456 123
	978 564 312
	312 897 645
	645 231 978
	231 645 897
	564 978 231
	897 312 564
*/
        int uniqueEntries=0;
        String[] storeRetrieved3x3Grid=new String[9];


        //OPTION 1 - USED TO TROUBLESHOOT ISSUES. IT DOES NOT RELY ON THE SET.
        //HENCE CAN BE SURE THAT SUDUKO IS REACHED EACH TIME


        do
        {
            String[] perm3x3 = new String[9];
            perm3x3[0]="1,2,3,4,5,6,7,8,9";
            perm3x3[1]="7,8,9,1,2,3,4,5,6";
            perm3x3[2]="4,5,6,7,8,9,1,2,3";
            perm3x3[3]="9,7,8,3,1,2,6,4,5";
            perm3x3[4]="5,6,4,8,9,7,2,3,1";
            perm3x3[5]="3,1,2,6,4,5,9,7,8";
            perm3x3[6]="2,3,1,5,6,4,8,9,7";
            perm3x3[7]="6,4,5,9,7,8,3,1,2";
            perm3x3[8]="8,9,7,2,3,1,5,6,4";

            String[] perm3x3Selection = new String[perm3x3.length];

            do
            {
                storeRetrieved3x3Grid[uniqueEntries]=perm3x3[uniqueEntries];
                //System.out.println("This has been chosen: " + perm3x3[storeRetrieved3x3Grid[uniqueEntries]] + " unique: " + uniqueEntries);
                uniqueEntries++;

            }while (uniqueEntries<9);

            //END OPTION 1   */

            permutationsSelected = new StringJoiner(",");

            //At this point, we know that storeRetrieved3x3Grid has the random numbers
            //and storing them in the array....
            //is there any use for random numbers
            //we are now concerned with

            for (String z: storeRetrieved3x3Grid)
            {
                //System.out.println("TEST: " + z);
                //System.out.println("GETTING ENTRY BACK OUT: " + z);
                entry3x3=z;


                temp[0][0]=convertStringTo3x3(entry3x3,0);
                temp[0][1]=convertStringTo3x3(entry3x3,2);
                temp[0][2]=convertStringTo3x3(entry3x3,4);
                temp[1][0]=convertStringTo3x3(entry3x3,6);
                temp[1][1]=convertStringTo3x3(entry3x3,8);
                temp[1][2]=convertStringTo3x3(entry3x3,10);
                temp[2][0]=convertStringTo3x3(entry3x3,12);
                temp[2][1]=convertStringTo3x3(entry3x3,14);
                temp[2][2]=convertStringTo3x3(entry3x3,16);

                /*
                System.out.println("String converted: " + temp[0][0]);
                System.out.println("String converted: " + temp[0][1]);
                System.out.println("String converted: " + temp[0][2]);
                System.out.println("String converted: " + temp[1][0]);
                System.out.println("String converted: " + temp[1][1]);
                System.out.println("String converted: " + temp[1][2]);
                System.out.println("String converted: " + temp[2][0]);
                System.out.println("String converted: " + temp[2][1]);
                System.out.println("String converted: " + temp[2][2]);
                */


                int first3x3GridSelected[][] = new int[3][3];

                if (totalNumbersProcessed<=81)
                {
                    if (totalNumbersProcessed<=27 && !condition2 && !condition3)
                    {
                        rowIndex=0;
                        colIndex=0;
                        condition1=true;
                        condition2=true;
                        condition3=true;
                    }

                    if (totalNumbersProcessed<=54 && totalNumbersProcessed>27 && condition1 && condition3)
                    {
                        rowIndex=3;
                        colIndex=0;
                        condition2=true;
                        condition1=false;
                        condition3=false;
                    }

                    if (totalNumbersProcessed<=81 && totalNumbersProcessed>54 && condition2 && !condition1)
                    {
                        rowIndex=6;
                        colIndex=0;
                        condition3=false;
                        condition1=true;
                        condition2=false;
                    }

                    if (numberOf3x3Processed==9)
                    {
                        switch(i)
                        {
                            case 1:
                                rowIndex=0;
                                break;
                            case 2:
                                rowIndex=0;
                                break;
                            case 3:
                                rowIndex=0;
                                break;
                            case 4:
                                rowIndex=3;
                                break;
                            case 5:
                                rowIndex=3;
                                break;
                            case 6:
                                rowIndex=3;
                                break;
                            case 7:
                                rowIndex=6;
                                break;
                            case 8:
                                rowIndex=6;
                                break;
                            case 9:
                                rowIndex=6;
                                break;
                        }
                    }
                    numberOf3x3Processed=0;

                    for (int n=0; n<temp.length;n++ )
                    {
                        if (colCount>=2 && rowCount!=2)
                        {
                            rowCount++;
                            colCount=0;
                            rowIndex++;

                            if (offset==0)
                            {
                                colIndex=0;
                            }
                            else
                            {
                                colIndex=offset;
                            }

                            if (colIndex==8 && numberOf3x3Processed==9)
                            {
                                colIndex=0;
                                rowIndex=rowIndex+3;
                            }

                            if (colIndex!=8 && numberOf3x3Processed==9)
                            {
                                colIndex=colIndex+1;
                                rowIndex=0;
                            }
                        }

                        for (int k=0; k<temp[0].length;k++)
                        {
                            numberOf3x3Processed++;

                            if (k==0)
                            {
                                offset=colIndex;
                            }

                            System.out.println("Selecting grid (3x3) " + i +" from : "+ s.size());
                            System.out.println("Total numbers processed so far: " + totalNumbersProcessed + " out of 81");
                            System.out.println("Current offset in 9x9 grid: " + offset);
                            System.out.println("Starting in this col in 9 x 9: " + colIndex);
                            System.out.println("The current coordinate(3x3):  " + "(" +rowCount +","+ colCount +")");
                            System.out.println("Following number chosen: " + temp[rowCount][colCount]);
                            System.out.println("being stored at coordinate(9x9): " + "(" + rowIndex + "," + colIndex +")");
                            System.out.println("currently processing this from 3 x 3:" + "(" + rowCount + "," +colCount+")");

                            sj.add(temp[rowCount][colCount] + "("+rowIndex+","+colIndex+")");

                            nineByNine[rowIndex][colIndex]=temp[rowCount][colCount];

                            realTime9x9Fill(sj.toString());
                            System.out.println("PERFORMED REAL TIME: " + sj.toString());
                            colCount++;
                            colIndex++;

                            if (numberOf3x3Processed==9)
                            {
                                colCount=0;
                                rowCount=0;
                            }

                            if (totalNumbersProcessed!=0 && totalNumbersProcessed%9==0)
                            {
                                System.out.println("row: " + failedRows);
                                System.out.println("col: " + failedColumns);
                                System.out.println("Numbers processed in 3x3 grid:" + numberOf3x3Processed);

                                if (numberOf3x3Processed==9)
                                {
                                    if (!failedRows&& !failedColumns)
                                    {
                                        successfulInputted3x3++;
                                    }
                                    else
                                    {
                                        successfulInputted3x3=0;
                                    }
                                }
                                System.out.println("Streak of successful 3x3 blocks: " + successfulInputted3x3);
                                i++;
                            }

                            if (totalNumbersProcessed%81==0)
                            {
                                System.out.println("IT HAS FILLED ENTIRE 9x9 BOARD");
                                completedBoards.put(numComplete9x9Boards,nineByNine);

                                print9x9Board(sj.toString());

                                numAttempts++;

                                //System.out.println("\n*********************Current sudoku board: " + numComplete9x9Boards + "  out of " + Permutations3x3into9x9 + "  Attempts: " + numAttempts);


                                totalNumbersProcessed=0;
                                i=1;

                                sj = new StringJoiner(" ");

                                if (sudokuComplete(failedRows, failedColumns))
                                {
                                    s = new HashSet(copyPermuations);

                                    sudokuSuccess=true;
                                }
                            }
                            totalNumbersProcessed++;
                        }
                    }
                }
            }

            storeRetrieved3x3Grid = new String[9];
            uniqueEntries=0;
            perm3x3 = s.toArray(new String[s.size()]);

        } while (numComplete9x9Boards.compareTo(numberPossibleBoards)==-1);
    }

    public void print9x9Board(String currentStringJoinerFullGrid)
    {
        String currentCompleted9x9Board=completedBoardsLogs[count];
        //System.out.println("STORING: " + currentStringJoinerFullGrid);
        prevNumComplete9x9Boards=new BigInteger(String.valueOf(permutationAllBoards.size()));
        permutationAllBoards.add(currentStringJoinerFullGrid);

        numComplete9x9Boards = new BigInteger(String. valueOf(permutationAllBoards.size()));
        //System.out.println("Previous permutations achieved: " + prevNumComplete9x9Boards + "Current permutations: " + numComplete9x9Boards);

        if((numComplete9x9Boards).compareTo(prevNumComplete9x9Boards)==1)
        {
            //System.out.println("\nThis is your board number " + (numComplete9x9Boards) + " summary: " + currentStringJoinerFullGrid + "\nPermutations selected: (" + permutationsSelected+")" + "minimum: "+ minimum + " maximum:" + maximum);
        }
        count=count+1;
    }

    public void realTime9x9Fill(String history)
    {
        int row=0;
        int col=0;
        int boardValue=0;
        int startLastNumber;

        int rowtoInt=0;
        int coltoInt=0;
        int boardValuetoInt=0;

        //System.out.println("\n"+history);

        // this means there is only one value in board since no space introduced by StringJoiner yet...
        if (history.lastIndexOf(" ")==-1)
        {
            row = Character.getNumericValue(history.charAt(2));
            col = Character.getNumericValue(history.charAt(4));
            boardValue= Character.getNumericValue(history.charAt(0));

            formattedBoard [row][col]=boardValue;
        }
        else
        {
            startLastNumber=history.lastIndexOf(" ");
            row = history.charAt((startLastNumber+3));
            col = history.charAt((startLastNumber+5));
            boardValue = history.charAt((startLastNumber+1));

            rowtoInt = Character.getNumericValue(row);
            coltoInt = Character.getNumericValue(col);
            boardValuetoInt= Character.getNumericValue(boardValue);

            formattedBoard [rowtoInt][coltoInt]=boardValuetoInt;
        }

        display9x9();

        checkUniqueRows(formattedBoard, rowIndex);
        checkUniqueColumns(formattedBoard, colIndex);
    }

    public void display9x9()
    {
        for (int i=0; i<formattedBoard.length; i++)
        {
            sj1= new StringJoiner("");

            for (int j=0; j<formattedBoard[0].length; j++)
            {
                sj1.add(Integer.toString(formattedBoard[i][j]));
            }

            if (totalNumbersProcessed==81)
            {
                System.out.println(sj1);
            }
        }
    }

    public boolean checkUniqueRows(int[][] nineByNine, int rowIndex)
    {
        summary1 = new StringJoiner("| ");

        int occurenceNumberRow=0;

        for (int j=0; j<possibleNumbers.length; j++)
        {
            occurenceNumberRow=0;

            for (int i=0; i<nineByNine[0].length; i++)
            {
                if (possibleNumbers[j]==nineByNine[rowIndex][i])
                {
                    occurenceNumberRow++;

                    if (occurenceNumberRow>1 && !failedRows)
                    {
                        failedRows = true;
                    }
                }
            }

            System.out.println("Number: " + possibleNumbers[j] + " has occured: " + occurenceNumberRow +  " times in  row " + rowIndex);
            summary1.add("N:" + String.valueOf(possibleNumbers[j]) + "  O:" + String.valueOf(occurenceNumberRow) + "  Row:" + String.valueOf(rowIndex));
        }

        return failedRows;
    }

    public boolean checkUniqueColumns(int[][] nineByNine, int colIndex)
    {
        summary = new StringJoiner("| ");
        int occurenceNumberCol=0;

        for (int j=0; j<possibleNumbers.length; j++)
        {
            occurenceNumberCol=0;

            for (int i=0; i<nineByNine.length; i++)
            {
                if (possibleNumbers[j]==nineByNine[i][colIndex])
                {
                    occurenceNumberCol++;

                    if (occurenceNumberCol>1 && !failedColumns)
                    {
                        failedColumns = true;
                    }
                }
            }
            System.out.println("Number: " + possibleNumbers[j] + " has occured: " + occurenceNumberCol +  " times in column " + colIndex);
            summary.add("N:" + String.valueOf(possibleNumbers[j]) + "  O:" + String.valueOf(occurenceNumberCol) + "  Col:" + String.valueOf(colIndex));
        }
        return failedColumns;
    }

    public boolean sudokuComplete(boolean duplicateNumbersRow, boolean duplicateNumbersCol)
    {
        if (duplicateNumbersRow || duplicateNumbersCol)   //if both are true, it means that sudoku has failed...
        {

            System.out.println("**************************");
            System.out.println("Better luck next time, failed on board:" + count + "\tPermutations selected: (" + permutationsSelected+")" + "  minimum: "+ minimum + " maximum:" + maximum);
            System.out.println("Moving onto Board Number: " + numComplete9x9Boards + "  Attempts: " + numAttempts);
            //System.out.println("COLUMN 8: N=Number, O=Occurrences Col = Column   "  + summary);
            //System.out.println("ROW 8: N=Number, O=Occurrences Row = Row   "  + summary1);
            //System.out.println("**************************");

            display9x9();
            wipe9x9Board(formattedBoard,nineByNine);

            if((numComplete9x9Boards).compareTo(prevNumComplete9x9Boards)==1)
            {
                System.out.println("Moving onto Board Number: " + numComplete9x9Boards + "  Attempts: " + numAttempts);
                permutationsSelected = new StringJoiner(",");
            }

            failedRows=false;
            failedRows=false;
            return false;
        }
        else
        {
            System.out.println("**************************");
            System.out.println("Congratulations, sudoku complete on board: " + count + " Permutations selected: (" + permutationsSelected+")");
            System.out.println("Complete solution:" + sj.toString());
            System.out.println("Moving onto Board Number: " + numComplete9x9Boards + "  Attempts: " + numAttempts);
            //System.out.println("COLUMN 8: N=Number, O=Occurrences Col = Column   "  + summary);
            //System.out.println("ROW 8: N=Number, O=Occurrences Row = Row   "  + summary1);
            System.out.println("**************************");
            permutationsSelected=new StringJoiner(",");

            //System.exit(0);

            if((numComplete9x9Boards).compareTo(prevNumComplete9x9Boards)==1)
            {
                System.out.println("Moving onto Board Number: " + numComplete9x9Boards + "  Attempts: " + numAttempts);
                permutationsSelected = new StringJoiner(",");
                prevNumComplete9x9Boards=new BigInteger(numComplete9x9Boards.toString());
            }

            display9x9();
            wipe9x9Board(formattedBoard,nineByNine);

            return true;
        }
    }
}

public class Permutation
{
    public static void main(String[] args)
    {
        System.out.println("Welcome to Online IDE!! Happy Coding :)");
        int originalNumber=9;
        int n=originalNumber;
        int r =9;
        Map <Integer, Long> m = new HashMap<>();
        System.out.println("***PERMUTATIONS***");
         System.out.println("P(n,r) = n! / (n−r)!");
        System.out.println("P(" + n+","+r+") = " + n+"!" + " / " + "("+n+"-"+r+")!");

        String Permutations3x3into9x9="108,883,584,818,776,183,656,945,007,213,012,309,135,068,193,536,000";
        String sudokuSolutions = "6,670,903,752,021,072,936,960";

        Sudoku sud = new Sudoku (Permutations (n,r,originalNumber, m),Permutations3x3into9x9);
    }

    public static long Permutations (int n, int r, int originalNumber, Map factorialResults)
    {
        long result=0;
        int temp;
        int denominator;

        if (originalNumber<r || r<0)
        {
            System.out.println("please enter n ≥ r ≥ 0");
            System.exit(0);
            return 0;
        }

        if (n>=1)
        {
            result = (n* (Permutations (n-1, r,originalNumber, factorialResults)));
            factorialResults.put(n,result);
            if (n==originalNumber)
            {
                denominator = originalNumber-r;
                if (factorialResults.containsKey(denominator))
                {
                    return result / (long)factorialResults.get(denominator); // this is number permutations
                }
            }
            return result;
        }
        return 1;
    }
}