import java.util.Random;
import java.util.Date;public class NQueenSimulatedAnnealing{
    private int[] board;
    private int[] test;
    private int dim;
    private Random ran;
    private double currentTemperature;
    private double coolingCoefficient;
    private int internalIter;               //number of swaps accepted.
    private int initialConflicts, currentConflicts, conflictsDifference;
    private int conflictPosition;           //a cursor to circulate the whole array, to record a conflict position    public static void main(String[] args){
//        int inDimension;
//        double inInitialTemperature, inInitialCoolingCoefficient;
//        if (args.length == 0){
//            System.out.println("At least the dimension of the board is necessary!");
//            return;
//        }
//        inDimension = Integer.parseInt(args[0]);
//        if (args.length > 1){
//            inInitialTemperature = Double.parseDouble(args[1]);
//            if (args.length > 2){
//                inInitialCoolingCoefficient = Double.parseDouble(args[2]);
//            }else{
//                inInitialCoolingCoefficient = 0.995;
//            }
//        }else{
//            inInitialTemperature = inDimension;
//            inInitialCoolingCoefficient = 0.995;
//        }
//        NQueenSimulatedAnnealing nqsa = new NQueenSimulatedAnnealing(inDimension);
//        System.out.println("Board dimension: " + nqsa.dim);
//        System.out.println("Initial Conflicts: " + nqsa.getConflicts());
//        nqsa.solve(inInitialTemperature, inInitialCoolingCoefficient);        NQueenSimulatedAnnealing nqsa = new NQueenSimulatedAnnealing(10000);
        System.out.println("Board dimension: " + nqsa.dim);
        System.out.println("Initial Conflicts: " + nqsa.getConflicts());
        nqsa.solve(1000, 0.99);
    }    public NQueenSimulatedAnnealing(){
        this(100);
    }    public NQueenSimulatedAnnealing(int dimension){
        dim = dimension;
        internalIter = 0;
        conflictPosition = 0;
        ran = new Random(new Date().getTime()); //new random sead
        board = new int[dim];
        for (int i = 0; i < dim; i++){          //set all Queens at the diagonal
            board[i] = i;
        }
        test = board.clone();                   //copy one copy of board to test.
        initialConflicts = currentConflicts = this.getConflicts();
    }    public void solve(double inInitialTemperature, double inCoolingCoefficient){
        currentTemperature = inInitialTemperature;
        coolingCoefficient = inCoolingCoefficient;
        testQueen();
        if (dim <= 50){
            display();
        }else{
            System.out.println("\nSolution found! Too large to print!");
        }
    }    private void testQueen(){
        int swap1, swap2;
        while(true){                                //control temperature
            while(true){                            //find an acceptable solution
                swap1 = findConflictPosition();         //first swap position: a conflict position
                swap2 = ran.nextInt(dim);               //second swap position: a random position
                swap(swap1, swap2);                     //swap, in array test[]
                conflictsDifference = getConflictsDifference(swap1, swap2);     //the differece after and before swap, by comparing board[] and test[]
                if (conflictsDifference < 0){           //a better solution
                    swapAccepted();                     //accept
                    break;
                }else{                                  //a worse solution
                    if(Math.exp(-conflictsDifference/currentTemperature) > ran.nextDouble()){   //still accepted by a certain probability
                        swapAccepted();
                        break;
                    }else{
                        test = board.clone();           //cancel the swap, by copy back from board[]
                    }
                }
            }
            printSwapSummary();                         //after a new solution is accepted, print the summary
            if (currentConflicts == 0 ){                //solved!
                break;
            }else{
                currentTemperature *= coolingCoefficient;       //decrease temperature
            }
        }
    }    private int findConflictPosition(){
        int i;
        while (true){
            for (i = 0; i < dim; i++){
                if(Math.abs(conflictPosition - i) == Math.abs(board[conflictPosition] - board[i])){     //conflict!
                    if (conflictPosition != i){
                        return conflictPosition;
                    }
                }
            }
            conflictPosition++;
            if (conflictPosition == dim) conflictPosition = 0;          //start from the beginning is it reaches the end
        }
    }    private int getConflictsDifference(int swap1, int swap2){   //only check the two Queens swapped, return the difference.
        int oldNumber = 0;
        int newNumber = 0;
        int i = 0;
        for (i = 0; i < dim; i++){
            if(Math.abs(swap1 - i) == Math.abs(board[swap1] - board[i])){
                oldNumber++;
            }
            if(Math.abs(swap2 - i) == Math.abs(board[swap2] - board[i])){
                oldNumber++;
            }
            if(Math.abs(swap1 - i) == Math.abs(test[swap1] - test[i])){
                newNumber++;
            }
            if(Math.abs(swap2 - i) == Math.abs(test[swap2] - test[i])){
                newNumber++;
            }
        }
        return newNumber - oldNumber;
    }    private int getConflicts(){                 //iteration to get the total conflicts
        int i, j;
        int counts = 0;
        for (i = 0; i < dim; i++){
            for (j = i + 1; j < dim; j++){
                int temp = test[i] - test[j];
                if (temp == i - j){
                    counts++;
                }else if(temp == j - i){
                    counts++;
                }
            }
        }
        return counts;
    }    private void swap(int i, int j){    //swap two columns, since only one queen per row and column
        int temp = test[i];
        test[i] = test[j];
        test[j] = temp;
    }    private void display(){
        int cursor = 0;
        System.out.printf("\n*** One Solution  ***\n");
        while(cursor < dim){
            for (int i = 0; i < test[cursor]; i++){
                System.out.print("- ");
            }
            System.out.print("Q ");
            for (int i = test[cursor] + 1; i < dim; i++){
                System.out.print("- ");
            }
            System.out.println();
            cursor++;
        }
        System.out.println("*** Solutions end ***\n");
    }    private void swapAccepted(){
         board = test.clone();
         currentConflicts += conflictsDifference;
    }    private void printSwapSummary(){
        double tempDraw;
        System.out.printf("%6d:%8d:%10.2f \t|", ++internalIter, currentConflicts, currentTemperature);
        tempDraw = 50. / initialConflicts * currentConflicts;
        for (int i = 1; i< tempDraw; i++){
            System.out.print("#");
        }
        System.out.print("\n");
    }}