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

public class FMMR{

    public static void main(String[] args){ 

	final double j = 0.3;     // Parameter in Update-Funktion
	final int n = 10;         // Dimension des Gitters
	int t = 1;
	boolean abbruch = false;
    
	/* unabhängige gleichverteilte Zufallsvariablen */
	Random uni = new Random(System.currentTimeMillis());
	Random uni1 = new Random(System.currentTimeMillis());
	Random uni2 = new Random(System.currentTimeMillis());
	int[] uni1_real;
	double[] uni2_real;

	/* Zustandvektoren und Anzahl schwarze und weisse Nachbarn eines Knotenpunktes */
	int[][] x = new int[1][n*n], x_schwarz = new int[1][n*n], x_weiss = new int[1][n*n];
	int[] min = new int[n*n], min_schwarz = new int[n*n], min_weiss = new int[n*n];
	int[] y = new int[n*n], 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;
		y[k] = 1; min[k] = -1;
		min_schwarz[k] = 0; y_weiss[k] = 0;
		if( i==0 || i==n-1){
		    if(l==0 || l==n-1){
			min_weiss[k] = 2;
			y_schwarz[k] = 2;
		    }
		    else{
			min_weiss[k] = 3;
			y_schwarz[k] = 3;
		    }
		}
		else{
		    if(l==0 || l==n-1){
			min_weiss[k] = 3;
			y_schwarz[k] = 3;
		    }
		    else{
			min_weiss[k] = 4;
			y_schwarz[k] = 4;
		    }
		}
	    }
	}
	
	x[0] = (int[])min.clone();
	x_weiss[0] = (int[])min_weiss.clone();
	x_schwarz[0] = (int[])min_schwarz.clone();
    

	while (abbruch == false){
	    t *= 2;
	    System.out.println("t = "+t);

	    // Initialisiere X (und die Anzahl der schwarzen und weissen Nachbarn) auf Minimalzustand
	    x = new int[t][n*n]; x_schwarz = new int[t][n*n]; x_weiss = new int[t][n*n];
	    uni1_real = new int[t];
	    uni2_real = new double[t];

	    for(int v=0; v < t; v++){

		uni1_real[v] = uni1.nextInt(n*n);
		uni2_real[v] = uni1.nextDouble();
	
		// Generiere MK X
		if(v == 0){
		    x[0] = (int[])min.clone();
		    x_weiss[0] = (int[])min_weiss.clone();
		    x_schwarz[0] = (int[])min_schwarz.clone();
		}
		else{
		    x[v] = (int[])x[v-1].clone();
		    x_weiss[v] = (int[])x_weiss[v-1].clone();
		    x_schwarz[v] = (int[])x_schwarz[v-1].clone();
		}

		k = uni1_real[v];

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

	    // MK Y berechnen
	    for(int v = t-1; v > 0; v--){
		k = uni1_real[v];
		y_old = y[k];

		// es wurde etwas geändert
		if(x[v][k] != x[v-1][k]){
		    if(x[v-1][k] == 1){
			y[k] = 1;
		    }
		    else{ 
			if (uni.nextDouble() <= ((1 + Math.exp(-2*j*(x_weiss[v][k]-x_schwarz[v][k])))/
						 (1 + Math.exp(-2*j*(y_weiss[k] - y_schwarz[k])))))
			    y[k] = -1;
			else
			    y[k] = 1;
		    }
		}
		// es wurde nichts geändert
		else{
		    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;}
		    }
		}

	    }
			 
	    // Abbruchbedingung überprüfen
	    abbruch = Arrays.equals(y, min);
	}
	    
	// 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[t-1][k]+" ");
	    }
	    System.out.println(line);
	    line = new String(" ");
	}
	
    }
}
