//ISING-MODELL - CFTP-Algorithmus
import java.util.Arrays;
import java.util.Random;

public class CFTP{

    public static void main(String[] args){ 
	final double j = 0.3;        // Parameter in Update-Funktion
	final int n = 10;         // Dimension des Gitters
	int t_old = 0, t = 1;
	boolean abbruch = false;

	/* unabhängige gleichverteilte Zufallsvariablen */
	Random uni1 = new Random(System.currentTimeMillis());
	Random uni2 = new Random(System.currentTimeMillis());
	int[] uni1_real = new int[t];
	double[] uni2_real = new double[t];

	int[] x = new int[n*n], y = new int[n*n];
	/* Anzahl der schwarzen und weissen Nachbarn eines Knotenpunktes */
	int[] x_schwarz = new int[n*n], x_weiss = new int[n*n];
	int[] y_schwarz = new int[n*n], y_weiss = new int[n*n];
	/* Hilfsvariablen */
	int k;
	double x_old, y_old;


        // Setze X0 = ^0 und Y0 = ^1
	for(int i=0; i< n; i++){
	    for(int l=0; l< n; l++){
		k=i*n+l;
		x[k] = -1; y[k] = 1; 
		x_schwarz[k] = 0; y_weiss[k] = 0;
		if( i==0 || i==n-1){
		    if(l==0 || l==n-1){
			x_weiss[k] = 2;
			y_schwarz[k] = 2;
		    }
		    else{
			x_weiss[k] = 3;
			y_schwarz[k] = 3;
		    }
		}
		else{
		    if(l==0 || l==n-1){
			x_weiss[k] = 3;
			y_schwarz[k] = 3;
		    }
		    else{
			x_weiss[k] = 4;
			y_schwarz[k] = 4;
		    }
		}
	    }
	}	

	// Generiere MK X und Y

	while (abbruch == false){
	    int[] dummy1 = new int[2*t];
	    double[] dummy2 = new double[2*t];
	    for(int v=0; v < t-t_old; v++){
		// Speichere alte PZZ, generiere neue PZZ
		dummy1[t_old+v] = uni1_real[v];
		dummy2[t_old+v] = uni2_real[v];
		dummy1[v] = uni1.nextInt(n*n); // wähle Knoten gleichverteilt aus 1,...,n*n aus
		dummy2[v] = uni2.nextDouble(); // generiere (0,1]-gleichverteilte PZZ U2,1 ... U2,T
	    }
	    uni1_real = dummy1;
	    uni2_real = dummy2;

	    t_old = t;
	    t *= 2;
	    System.out.println("t = "+t);
		    
	    for(int v=0; v<t; v++){
		k = uni1_real[v];

		// MK X updaten:
		x_old = x[k];
		if (uni2_real[v] < 1/(1 + Math.exp(-2*j*(x_schwarz[k] - x_weiss[k]))) )
		    x[k] = 1;
		else
		    x[k] = -1;
		
		// falls geändert: x_weiss, x_schwarz der Nachbarn anpassen
		if(x_old != x[k]){
		    if(k-n > -1){
			if(x[k] == 1){ x_schwarz[k-n] +=1; x_weiss[k-n] -=1;}
			else{          x_schwarz[k-n] -=1; x_weiss[k-n] +=1;}
		    }
		    if( (k+1) % n != 0){
			if(x[k] == 1){ x_schwarz[k+1] +=1; x_weiss[k+1] -=1;}
			else{          x_schwarz[k+1] -=1; x_weiss[k+1] +=1;}
		    }
		    if( k+n < n*n){
			if(x[k] == 1){ x_schwarz[k+n] +=1; x_weiss[k+n] -=1;}
			else{          x_schwarz[k+n] -=1; x_weiss[k+n] +=1;}
		    } 
		    if( k % n != 0){
			if(x[k] == 1){ x_schwarz[k-1] +=1; x_weiss[k-1] -=1;}
			else{          x_schwarz[k-1] -=1; x_weiss[k-1] +=1;}
		    }
		}
		    	
		// MK Y updaten:
		y_old = y[k];
		if (uni2_real[v] < 1/(1 + Math.exp(-2*j*(y_schwarz[k] - y_weiss[k]))) )
		    y[k] = 1;
		else
		    y[k] = -1;
		
		// falls geändert: y_weiss, y_schwarz der Nachbarn anpassen
		if(y_old != y[k]){
		    if(k-n > -1){
			if(y[k] == 1){ y_schwarz[k-n] +=1; y_weiss[k-n] -=1;}
			else{          y_schwarz[k-n] -=1; y_weiss[k-n] +=1;}
		    }
		    if( (k+1) % n != 0){
			if(y[k] == 1){ y_schwarz[k+1] +=1; y_weiss[k+1] -=1;}
			else{          y_schwarz[k+1] -=1; y_weiss[k+1] +=1;}
		    }
		    if( k+n < n*n){
			if(y[k] == 1){ y_schwarz[k+n] +=1; y_weiss[k+n] -=1;}
			else{          y_schwarz[k+n] -=1; y_weiss[k+n] +=1;}
		    } 
		    if( k % n != 0){
			if(y[k] == 1){ y_schwarz[k-1] +=1; y_weiss[k-1] -=1;}
			else{          y_schwarz[k-1] -=1; y_weiss[k-1] +=1;}
		    }
		}
		             
	    } // for v
         

	    abbruch = Arrays.equals(x,y);
	} // while  

	// Ausgabe erstellen
	String line = new String(" ");
	for(int i=0; i< n; i++){
	    for(int l=0; l< n; l++){
		k=i*n+l;
		line += new String(x[k]+" ");
	    }
	    System.out.println(line);
	    line = new String(" ");
	}
    }
}
