//import java.util.*;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;

import javax.swing.JFrame;

public class Board {

	protected Float[][] board;
	protected int[][] input;
	static ArrayList<Position> clustersizes = new ArrayList<Position>();
	static int mindsovielgrößer = 2;
	public static int connections = 20;
	
	public Board(int i){
		board = new Float[i][i];
		input = new int[i][i];
	}
	
	public Board(int i, int j){
		board = new Float[i][j];
		input = new int[i][j];
	}
	
	public Board(Float[][] data){
		board = data;
		input = new int[data.length][data[1].length];
	}
	
	public Board (int[][] data){
		board = new Float[data.length][data[1].length];
		input = data;
	}
	
	public void setInput(int i, int j,Float k){
		board[i][j] = k;
	}
	
	public void setInput(int i, int j,int k){
		input[i][j] = k;
	}
	
	public void inputPlus(Position hier){
		input[hier.getx()][hier.gety()]++;
	}
	
	public void inputPlus(int i, int j) {
		input[i][j]++;
	}
	
	public Float getEntry(int i, int j){
		return board[i][j];
	}
	
	public Float[][] getData(){
		return board;
	}
	
	public int[][] getInput(){
		return input;
	}
	
	public int getInput(int i,int j){
		return input[i][j];
	}
	
	public int[] size(){
		int[] size = {this.getData().length,this.getData()[1].length };
		return size;
	}
	
	public int boardmax(){
		int max=0;
		for(int i=0;i<=this.size()[0]-1;i++){
			for(int j=0;j<=this.size()[1]-1;j++){
				if(max<input[i][j]){
					max=input[i][j];
				}
			}
		}
		return max;
	}
	
	public Position maxPos(){
		int x=0;
		int y=0;
		int max=0;
		for(int i=0;i<this.size()[0];i++){
			for(int j=0;j<this.size()[1];j++){
				if(max<this.getInput(i, j)){
					max=this.getInput(i, j);
					x=i;
					y=j;
				}
			}
		}
		Position pos = new Position(x,y);
		return pos;
	}
	
	
	public int boardmin(){
		int min=999999999;
		for(int i=0;i<=this.size()[0]-1;i++){
			for(int j=0;j<=this.size()[1]-1;j++){
				if(min>this.input[i][j]){
					min=this.input[i][j];
				}
			}
		}
		return min;
	}
	
	public float boardave(){
		float ave=0;
		for(int i=0;i<=this.size()[0]-1;i++){
			for(int j=0;j<=this.size()[1]-1;j++){
				ave=ave+input[i][j];
			}
		}
		ave=ave/this.size()[0]/this.size()[1];
		return ave;
	}
	
	//never delete
	public void input2board(){
		for(int i=0;i<=this.size()[0]-1;i++){
			for(int j=0;j<=this.size()[1]-1;j++){
				this.setInput(i, j, input[i][j]/( (float) this.boardmax()));
			}
		}
	}
	
	public void clear(){
		int size1=this.size()[0];
		int size2=this.size()[1];
		for(int i=0;i<=size1-1;i++){
			for(int j=0;j<=size2-1;j++){
				input[i][j]=0;
			}
		}
		this.input2board();
	}
	
	public int points(){
		int points = 0;
		for(int i=0;i<this.size()[0];i++){
			for(int j=0;j<this.size()[1];j++){
				points=points+this.getInput(i, j);
			}
		}
		return points;
	}
	
	public void random(int k){
		int size1=this.size()[0];
		int size2=this.size()[1];
		for(int i=0;i<k+1;i++){
			input[(int) (size1 * Math.random())][(int) (size2 * Math.random())]++;
		}
		this.input2board();
	}
	
	public int countpositiv(){
		int count=0;
		for(int i=0;i<this.size()[0];i++){
			for(int j=0;j<this.size()[1];j++){
				if(this.getInput(i, j)!=0){
					count++;
				}
			}
		}
		return count;
	}
	
	public Position[] board2Position(){
		ArrayList<Position> position = new ArrayList<Position>();
		for(int i=0;i<this.size()[0];i++){
			for(int j=0;j<this.size()[1];j++){
				if(this.getInput(i, j)!=0){
					Position a = new Position(i,j);
					position.add(a);
				}
			}
		}
		Position[] pos = new Position[position.size()];
		pos = position.toArray(pos);
		return pos;
	}
	
	public int positivPositions(){
		int size=0;
		for(int i=0;i<this.size()[0];i++){
			for(int j=0;j<this.size()[1];j++){
				if(this.getInput(i, j)!=0){
					size++;
				}
			}
		}
		return size;
	}
	
	
	//deletes all Entrys from board and sets all Grid-Position from the Position-Array to 1.
	public void pos2Board(Position[] pos){
		this.clear();
		for(int i=0;i<pos.length;i++){
			this.setInput(pos[i].getx(), pos[i].gety(), 1);
		}
		this.input2board();
	}
	
	//checks if the corresponding grid-positions of two boards are either positive or zero. 
	public boolean identBlack(Board be){
		for(int i=0;i<this.size()[0];i++){
			for(int j=0;j<this.size()[1];j++){
				if(this.getInput(i, j)==0 && be.getInput(i, j)!=0 ){
					return false;
				}
				if(this.getInput(i, j)!=0 && be.getInput(i, j)==0 ){
					return false;
				}
				
			}
		}
		return true;
	}
	
	public void map2board(Board data){
		this.clear();
		Walk tet = new Walk(data);
		tet.jump(Levy.jump);
		ArrayList<Position> map = tet.getMap();
		int lang = map.size();
		for(int i=0;i<lang;i++){
			this.inputPlus(map.get(i));
		}
		this.input2board();
	}
	
	//Computes the average value of a board and creates a new board, where the values are zero if they aren't at least d times over the average. Else they are as in the original.
	public Board cutLevel(double d){
		Board bebob = new Board(this.size()[0],this.size()[1]);
		bebob.clear();
		float ave = this.boardave();
		for(int i=0;i<bebob.size()[0];i++){
			for(int j=0;j<bebob.size()[1];j++){
				if(this.getInput()[i][j]>d*ave){
					bebob.setInput(i, j, this.getInput()[i][j]);
				}
			}
		}
		bebob.input2board();
		return bebob;
	}
	
	public void rescale(double d) {
		for(int i=0;i<this.size()[0];i++){
			for(int j=0;j<this.size()[1];j++){
				float k = (float) (this.getEntry(i, j)*d);
				this.setInput(i, j, k);
			}
		}
	}
	
	//Copys the values from one board to another.
	public void copy(Board boo) {
		for(int i=0;i<boo.size()[0];i++){
			for(int j=0;j<boo.size()[1];j++){
				this.setInput(i, j, boo.getInput(i, j));
			}
		}
		this.input2board();
	}
	
	//Sets a values from this-Board to zero, when Boo-Board isn't zero there.
	public void delete(Board boo, int ersatz){
		for(int i=0;i<this.size()[0];i++){
			for(int j=0;j<this.size()[1];j++){
				if(boo.getInput(i, j)!=0){
					this.setInput(i, j, ersatz);
				}
			}
		}
		this.input2board();
	}
	
	//sets all entries to 0, if boo is zero there
	public void delete(Board boo){
		for(int i=0;i<this.size()[0];i++){
			for(int j=0;j<this.size()[1];j++){
				if(boo.getInput(i, j)==0){
					this.setInput(i, j, 0);
				}
			}
		}
		this.input2board();
	}
	
	//Adds the values of boo to the this.board. 
	public void add(Board boo){
		for(int i=0;i<this.size()[0];i++){
			for(int j=0;j<this.size()[1];j++){
				if(boo.getInput(i, j)!=0){
					this.setInput(i, j, this.getInput(i, j)+boo.getInput(i, j));
				}
			}
		}
		this.input2board();
	}
	
	//Sets the value of the this-board to k, if boo isn't zero there. 
	public void add(Board boo, int k){
		for(int i=0;i<this.size()[0];i++){
			for(int j=0;j<this.size()[1];j++){
				if(boo.getInput(i, j)!=0){
					this.setInput(i, j, k);
				}
			}
		}
		this.input2board();
	}
	
	//Sets the value of a new board to 1, if the this- and be-board are both positiv there. Else its zero.
	public Board intersect(Board be){
		Board boo = new Board(this.size()[0],this.size()[1]);
		boo.clear();
		for(int i=0;i<boo.size()[0];i++){
			for(int j=0;j<boo.size()[1];j++){
				if(this.getInput(i, j)!=0 && be.getInput(i, j)!=0){
					boo.setInput(i, j, 1);
				}
			}
		}
		boo.input2board();
		return boo;
	}
	
	//Sets the values of a new Board to the multiplicative of the respective values of the this- and be-board.
	public Board multiply(Board be){
		Board boo = new Board(this.size()[0],this.size()[1]);
		boo.clear();
		int a,b,c;
		for(int i=0;i<boo.size()[0];i++){
			for(int j=0;j<boo.size()[1];j++){
					a=this.getInput(i, j);
					b=be.getInput(i, j);
					c=a*b;
					boo.setInput(i, j, c);
			}
		}
		boo.input2board();
		return boo;
	}
	
	//Plotting-Kram
	
	public void plot(String stil, String name,  int placex, int placey){
		JFrame frame = new JFrame(name);
        frame.setLocation(placex, placey);
        frame.setSize(this.size()[0]*Paint.pixel+25,this.size()[0]*Paint.pixel+60);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(new Paint(this, stil));
        frame.setVisible(true);
    }
	
	public void plot(int placex, int placey){
		this.plot("", "", placex, placey);
	}
	
	//kopiert das board, löscht die punkte unter einem gew level aus und plottet es
	public void plot(double d,String stil, String name,  int placex, int placey){
		
		Board bebob = new Board(this.getInput());
		float ave = this.boardave();
		
		for(int i=0;i<bebob.size()[0];i++){
			for(int j=0;j<bebob.size()[1];j++){
				if(bebob.getInput()[i][j]<d*ave){
					bebob.setInput(i, j, 0);
				}
			}
		}
		bebob.input2board();
		
		JFrame fray = new JFrame(name);
        fray.setLocation(placex, placey);
        fray.setSize(this.size()[0]*Paint.pixel+25,this.size()[0]*Paint.pixel+60);
        fray.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        fray.add(new Paint(bebob, stil));
        fray.setVisible(true);
	}
	
	//Cluster, die eingefügt werden können 
	
	//rechteckiger cluster
	public void Rect(int x, int y, int length, int height,int points){
		Board temp = new Board(this.size()[0],this.size()[1]);
		temp.clear();
		int xr,yr;
		for(int i=0;i<points;i++){
			xr=x+ (int) (Math.random()*length);
			yr=y+ (int) (Math.random()*height);
			if(0<=xr && xr<(Levy.size1-1) && 0<=yr && yr<(Levy.size2-1)){
				temp.input[xr][yr]++;
			}
		}	
		temp.input2board();
		temp.clearsingles();
		Levy.ideal.add(temp, Levy.colour);
		Levy.colour++;
		this.add(temp);
		this.input2board();
	}
	
	//gauss-cluster
	public void Gauss(int ewx, int ewy, float varx, float vary, int points){
		Board temp = new Board(this.size()[0],this.size()[1]);
		temp.clear();
		int xr,yr;
		int size1=this.size()[0];
		int size2=this.size()[1];
		Random random = new Random();
		for(int j=0;j<points;j++){
			double a=random.nextGaussian();
			double b=random.nextGaussian();
			
			if((a*a+b*b)<6){
			    xr=(int) (ewx+ a*varx);
			    yr=(int) (ewy+ b*vary);
				if(0<=xr && xr<size1 && 0<=yr && yr<size2){
				    temp.input[xr][yr]++;
				}
			}

		}
		temp.input2board();
		temp.clearsingles();
		Levy.ideal.add(temp, Levy.colour);
		Levy.colour++;
		this.add(temp);
		this.input2board();
	}
	
	public void TripleGauss(int ewx1, int ewy1,int ewx2, int ewy2,int ewx3, int ewy3, float var, int points){
		Board temp = new Board(this.size()[0],this.size()[1]);
		temp.clear();
		int xr,yr;
		int size1=this.size()[0];
		int size2=this.size()[1];
		Random random = new Random();
		for(int j=0;j<(points/3);j++){
			double a=random.nextGaussian();
			double b=random.nextGaussian();
			if((a*a+b*b)<6){
			    xr=(int) (ewx1+ a*var);
			    yr=(int) (ewy1+ b*var);
				if(0<=xr && xr<size1 && 0<=yr && yr<size2){
				    temp.input[xr][yr]++;
				}
			}
		}
		for(int j=0;j<(points/3);j++){
			double a=random.nextGaussian();
			double b=random.nextGaussian();
			if((a*a+b*b)<6){
			    xr=(int) (ewx2+ a*var);
			    yr=(int) (ewy2+ b*var);
				if(0<=xr && xr<size1 && 0<=yr && yr<size2){
				    temp.input[xr][yr]++;
				}
			}
		}		
		for(int j=0;j<(points/3);j++){
			double a=random.nextGaussian();
			double b=random.nextGaussian();
			if((a*a+b*b)<6){
			    xr=(int) (ewx3+ a*var);
			    yr=(int) (ewy3+ b*var);
				if(0<=xr && xr<size1 && 0<=yr && yr<size2){
				    temp.input[xr][yr]++;
				}
			}
		}
		temp.input2board();
		temp.clearsingles();
		Levy.ideal.add(temp, Levy.colour);
		Levy.colour++;
		this.add(temp);
		this.input2board();
	}
	
	//sichelförmiger cluster
	public void cCluster(Position a, double d, int points){
		Board temp = new Board(this.size()[0],this.size()[1]);
		temp.clear();
		int size1=this.size()[0];
		int size2=this.size()[1];
		Random rando = new Random();
		
		double xr=a.getx();
		double yr=a.gety();
		double as= 0.877;
		double bs= -0.479;
		double cs= 0.479;
		double ds= 0.877;
		for(int i=0;i<points;i++){
			double x=0,y=0,xx=0,yy=0;
			x=rando.nextGaussian()*2*d;
			y=rando.nextGaussian()*d;
			y=y+Math.abs(x*rando.nextGaussian());
			
			xx=as*x+bs*y;
			yy=cs*x+ds*y;
			
			xx=xx+xr;
			yy=yy+yr;
			if(0<=xx && xx<size1 && 0<=yy && yy<size2){
				temp.input[(int) xx][(int) yy]++;
			}
			
		}	
		temp.input2board();
		temp.clearsingles();
		Levy.ideal.add(temp, Levy.colour);
		Levy.colour++;
		this.add(temp);
		this.input2board();
	}
	
	public void Kante(Position a, double d, int points){
		Board temp = new Board(this.size()[0],this.size()[1]);
		temp.clear();
		int size1=this.size()[0];
		int size2=this.size()[1];
		Random rando = new Random();
		
		double xr=a.getx();
		double yr=a.gety();
		double as= 0.877;
		double bs= -0.479;
		double cs= 0.479;
		double ds= 0.877;
		for(int i=0;i<points;i++){
			double x=0,y=0,xx=0,yy=0;
			x=rando.nextGaussian()*2*d;
			y=rando.nextGaussian()*d;
			y=y+Math.abs(x);
			
			xx=as*x+bs*y;
			yy=cs*x+ds*y;
			
			xx=xx+xr;
			yy=yy+yr;
			if(0<=xx && xx<size1 && 0<=yy && yy<size2){
				temp.input[(int) xx][(int) yy]++;
			}
			
		}	
		temp.input2board();
		temp.clearsingles();
		Levy.ideal.add(temp, Levy.colour);
		Levy.colour++;
		this.add(temp);
		this.input2board();
	}
	
	//Gugelhupf-cluster
	public void Gugel(int ewx, int ewy, float dist, float var, int points){
		Board temp = new Board(this.size()[0],this.size()[1]);
		temp.clear();
		int xr,yr;
		float dir1, dir2;
		int size1=this.size()[0];
		int size2=this.size()[1];
		Random random = new Random();
		Random randor = new Random();
		for(int j=0;j<points;j++){
			dir1= (float) randor.nextGaussian();
			dir2= (float) randor.nextGaussian();
			float norm = (float) Math.sqrt(dir1*dir1+dir2*dir2);
			if(norm!=0){
				dir1=dir1/norm;
				dir2=dir2/norm;
				float ra = (float) random.nextGaussian();
				if(ra<3){
				    xr=(int) (ewx+ dir1*(dist+(ra*var)));
				    yr=(int) (ewy+ dir2*(dist+(ra*var)));
					if(0<=xr && xr<size1 && 0<=yr && yr<size2){
					    temp.input[xr][yr]++;
					}
				}
			}
		}
		temp.input2board();
		temp.clearsingles();
		Levy.ideal.add(temp, Levy.colour);
		Levy.colour++;
		this.add(temp);
		this.input2board();
	}
	
	//schiefes random-noise
	public void lopsidednoise(int k){
		int size1=this.size()[0];
		int size2=this.size()[1];
		for(int i=0;i<k+1;i++){
			int x = (int) (size1 * Math.random());
			int y = (int) (size2 * Math.random());
			int z = (int) (size1 * Math.random());
			if(x>z){
				input[x][y]++;
			}
		}
		this.input2board();
	}
	
	//linear zur mitte hin ansteigendes noise
	public void middlesidednoise(int k){
		int size1=this.size()[0];
		int size2=this.size()[1];
		for(int i=0;i<k+1;i++){
			int x = (int) (size1 * Math.random());
			int y = (int) (size2 * Math.random());
			int z = (int) (size1 * Math.random());
			if(x>z){
				input[(int) (x/2)][y]++;
			}
		}
		for(int i=0;i<k+1;i++){
			int x = (int) (size1 * Math.random());
			int y = (int) (size2 * Math.random());
			int z = (int) (size1 * Math.random());
			if(x<z){
				input[(int) (x/2+size1/2)][y]++;
			}
		}
		
		this.input2board();
	}
	
	//zur mitte ansteigendes noise, aber ohne kante.
	public void middlesmoothnoise(int k){
		int size1=this.size()[0];
		int size2=this.size()[1];
		Random gauss = new Random();
		Random gleich = new Random();
		for(int i=0;i<k+1;i++){
			int y = (int) (gleich.nextFloat()*size2);
			int x = (int) (gauss.nextGaussian()*size1/2+24);
			if(25<x && x<size1){
				input[x][y]++;
			}
		}
		for(int i=0;i<(int)(k/7.3);i++){
			int y = (int) (gleich.nextFloat()*size2);
			int x = (int) (gleich.nextFloat()*26);
			input[x][y]++;
		}
		this.input2board();
	}

	//vollautomatisch Cluster suchen und aus dem Data-Board löschen
	public void searchanddestroy(int jump, int connections, int stop, int colour){
		Walk tet = new Walk(Levy.data);
		tet.jump(jump);
		
		Walksort waso = new Walksort(tet.size[0],tet.size[1]);
		waso.initialize(tet);
		
		Board bebe = new Board(tet.getLevycount());
		bebe.input2board();	
		
		if(Levy.plot>0){
			Levy.data.plot("blac", "Plot", 10, 10);
			bebe.plot(1.8,"blac", "Levy-Walk", Levy.data.size()[0]*Paint.pixel+30, 10);
			bebe.plot(1.8,"black", "Levy-Walk black", 2*Levy.data.size()[0]*Paint.pixel+30, 10);
		}

		Board neu = tet.clusterfind(connections, stop, waso);
		neu.clearsingles();
		Levy.data.delete(neu,0);
		neu.addsingles(colour);

		int pospos = neu.positivPositions();
		if(pospos>Levy.ignoreab){
			Board.clustersizes.add(new Position(colour,pospos));
			Levy.cluster.add(neu,colour);
		}
		
		if(Levy.plot>0){
			Levy.data.plot("Board", "Board", 10, 280);
			Levy.cluster.plot("colour", "Cluster", Levy.data.size()[0]*Paint.pixel+30, 280);
		}
	}
	
	public Integer[] touchescluster(int clu) {
		int size1=this.size()[0];
		int size2=this.size()[1];
		ArrayList<Integer> reto = new ArrayList<Integer>();
		
		for(int i=1;i<size1-1;i++){
			for(int j=1;j<size2-1;j++){
				
				if(this.getInput(i,j)==clu){
					for(int a=-1;a<2;a++){
						for(int b=-1;b<2;b++){
							if(Levy.cluster.getInput(i-a, j-b)!=0 && Levy.cluster.getInput(i-a, j-b)!=clu){
								reto.add(getInput(i-a, j-b));
							}
						}
					}
				}
				
			}
		}
		Integer[] retour = new Integer[reto.size()];
		retour = reto.toArray(retour);
		return retour;
	}
	
	
	public int[] colour2index(int[][] clust1sizes) {
		int max = 0;
		for(int i=0;i<clust1sizes.length;i++){
			if(clust1sizes[i][0]>max){
				max=clust1sizes[i][0];
			}
		}
		int[] ausgabe= new int[max+1];
		for(int i=0;i<clust1sizes.length;i++){
			ausgabe[clust1sizes[i][0]]=i;
		}
		return ausgabe;
	}
	
	
	//löschen?
	public int colour2index(int[][] clust1sizes, int colour) {
		int ausgabe=0;
		for(int i=0;i<clust1sizes.length;i++){
			if(clust1sizes[i][0]==colour){
				ausgabe=i;
				i=clust1sizes.length;
			}
		}
		return ausgabe;
	}
	
	public Integer[] colour2index(Integer[] clu) {
		Integer[] retour = new Integer[clu.length];
		for(int i=0;i<clu.length;i++){
			for(int j=0;j<Board.clustersizes.size();j++){
				if(Board.clustersizes.get(j).getx()==clu[i]){
					retour[i]=j;
				}
			}
		}
		return retour;
	}
	
	public void joinclusterparts(){
		this.reducecolour();
		int size1=this.size()[0];
		int size2=this.size()[1];
		int max=this.boardmax()+1;
		int[] sizes = new int[max];
		for(int i=0;i<size1;i++){
			for(int j=0;j<size2;j++){
				sizes[this.getInput(i, j)]++;
			}
		}
		int [][] schnitte = new int[max][max];
		for(int i=1;i<size1-1;i++){
			for(int j=1;j<size2-1;j++){
				int a = this.getInput(i, j);
				if(a!=0){
					if(this.getInput(i-1, j)!=0 && this.getInput(i-1, j)!=a){ schnitte[a][this.getInput(i-1, j)]++;}
					if(this.getInput(i+1, j)!=0 && this.getInput(i+1, j)!=a){ schnitte[a][this.getInput(i+1, j)]++;}
					if(this.getInput(i, j-1)!=0 && this.getInput(i, j-1)!=a){ schnitte[a][this.getInput(i, j-1)]++;}
					if(this.getInput(i, j+1)!=0 && this.getInput(i, j+1)!=a){ schnitte[a][this.getInput(i, j+1)]++;}
				}
			}
		}
		for(int i=1;i<max;i++){
			for(int j=1;j<max;j++){
				if(schnitte[i][j]>0 && sizes[j]>0 && sizes[i]>0){
					if(sizes[i]>sizes[j] && schnitte[j][i]*25>sizes[j]){
							this.change(i, j);
							sizes[j]=0;
							schnitte[i][j]=0;
							schnitte[j][i]=0;
							for(int k=1;k<max;k++){
								schnitte[i][k]=schnitte[i][k]+schnitte[j][k];
							}
							i=1;
							j=1;
					}
					if(sizes[j]>sizes[i] && schnitte[i][j]*25>sizes[i]){
						this.change(j, i);
						sizes[i]=0;
						schnitte[j][i]=0;
						schnitte[i][j]=0;
						for(int k=1;k<max;k++){
							schnitte[j][k]=schnitte[j][k]+schnitte[i][k];
						}
						i=1;
						j=1;
				}
				}
			}
		}
		this.input2board();
	}
	
	//alt - noch nicht löschen
	/*public void joinclusterparts(){
		boolean genug=false;
		//System.out.println(genug);
		while(genug==false){
			//System.out.println(genug);
			for(int i=0;i<Board.clustersizes.size();i++){
				//System.out.println(genug);
				genug=true;
				//System.out.println(genug);
				Position jetzt = Board.clustersizes.get(i);
				Integer[] touchescluster = Levy.cluster.touchescluster(jetzt.getx());
				Integer[] col2index = Levy.cluster.colour2index(touchescluster);
				for(int j=0;j<touchescluster.length;j++){
					if(jetzt.gety()>Board.mindsovielgrößer*Board.clustersizes.get(col2index[j]).gety() || Board.clustersizes.get(col2index[j]).gety()>Board.mindsovielgrößer*jetzt.gety()){
						
						if(jetzt.gety()!=0 && Board.clustersizes.get(col2index[j]).gety()!=0){
							Levy.cluster.change(jetzt.getx(),Board.clustersizes.get(col2index[j]).getx());
							int neo = jetzt.gety()+Board.clustersizes.get(col2index[j]).gety();
							Board.clustersizes.get(i).setY(neo);
							Board.clustersizes.get(col2index[j]).setY(0);
							genug=false;
							/*System.out.println(genug);
							for(int m=0;m<Board.clustersizes.size();m++){
								Board.clustersizes.get(m).print();
							}
						}

					} 
				}
			}
		}
	}*/
	
	public ArrayList<Integer> colours(){
		int size1 = this.size()[0];
		int size2 = this.size()[1];
		ArrayList<Integer> col = new ArrayList<Integer>();
		for(int i=0;i<size1;i++){
			for(int j=0;j<size2;j++){
				if(this.getInput(i, j)!=0){
					if(col.contains(this.getInput(i, j))){	}
					else{ col.add(this.getInput(i, j)); }
				}
			}
		}
		return col;
	}
	
	public void reducecolour(){
		ArrayList<Integer> col = this.colours();
		Collections.sort(col);

		int si = col.size();
		for(int i=1;i<=si;i++){
			if(col.contains(i)){}
			else{ 
				this.change(i, col.get(col.size()-1));
				col.remove(col.size()-1);
			}
		}

	}
	
	
	//von b zu a
	public void change(int a, int b) {
		for(int i=0;i<this.size()[0];i++){
			for(int j=0;j<this.size()[1];j++){
				if(this.getInput(i, j)==b){
					this.setInput(i, j, a);
				}
			}
		}
		this.input2board();
	}

	public void clearsingles() {
		int size1=this.size()[0];
		int size2=this.size()[1];
		for(int i=1;i<size1-1;i++){
			for(int j=1;j<size2-1;j++){
				if(this.getInput(i-1,j)==0 && this.getInput(i+1,j)==0 && this.getInput(i,j-1)==0 && this.getInput(i,j+1)==0){
					this.setInput(i, j, 0);
				}
			}
		}
		this.input2board();
	}
	
	public void addsingles(int col) {
		int size1=this.size()[0];
		int size2=this.size()[1];
		Board temp = new Board(size1,size2);
		temp.copy(this);
		for(int i=1;i<size1-1;i++){
			for(int j=1;j<size2-1;j++){
				int count = 0;
				if(temp.getInput(i-1,j)!=0){count++; }
				if(temp.getInput(i+1,j)!=0){count++; }
				if(temp.getInput(i,j+1)!=0){count++; }
				if(temp.getInput(i,j-1)!=0){count++; }
				if(count>2){
					this.setInput(i, j, col);
				}
			}
		}
		this.input2board();
	}
	
	public void board2file(String s) throws IOException {
		FileWriter fw = new FileWriter(s);
        BufferedWriter bw = new BufferedWriter(fw);
        bw.write("x="+this.size()[0]+" "+"y="+this.size()[1]);
        bw.newLine();
        for(int i=0;i<this.size()[0];i++){
        	for(int j=0;j<this.size()[1];j++){
        		bw.write(""+this.getInput(i, j));
        		bw.newLine();
            }
        }
        bw.close();
	}
	
	public void board2file(String s, String zusatz) throws IOException {
		FileWriter fw = new FileWriter(s);
        BufferedWriter bw = new BufferedWriter(fw);
        bw.write("x="+this.size()[0]+" "+"y="+this.size()[1]+"; "+zusatz);
        bw.newLine();
        for(int i=0;i<this.size()[0];i++){
        	for(int j=0;j<this.size()[1];j++){
        		bw.write(""+this.getInput(i, j));
        		bw.newLine();
            }
        }
        bw.close();
	}
	
	public void board2arff(String Pfad,Board ideal) throws IOException{
		FileWriter fw = new FileWriter(Pfad);
        BufferedWriter bw = new BufferedWriter(fw);
        this.input2board();
        this.reducecolour();
        String[] classes = new String[ideal.boardmax()+1];
        System.out.println();
		Random rando = new Random();
        String s="";
        for(int i=0;i<classes.length-1;i++){
        	classes[i]="class"+i;
        	s=s+"class"+i+",";
        }
        classes[classes.length-1]="class"+(classes.length-1);
        s=s+"class"+(classes.length-1);
        
        bw.write("@RELATION clu");
        bw.newLine();
        bw.newLine();
        bw.write("@ATTRIBUTE xaxis	INTEGER");
        bw.newLine();
        bw.write("@ATTRIBUTE yaxis 	INTEGER");
        bw.newLine();
        bw.write("@ATTRIBUTE class 	{"+s+"}");
        bw.newLine();
        bw.newLine();
        bw.write("@DATA");
        bw.newLine();
        for(int i=0;i<this.size()[0];i++){
        	for(int j=0;j<this.size()[0];j++){
        		int zahl = this.getInput(i, j);
        		for(int m=0;m<zahl;m++){
					int a = rando.nextInt(100);
					int b = rando.nextInt(100);
					bw.write(i+"."+a+","+j+"."+b+","+classes[ideal.getInput(i, j)]);
        	     	//bw.write(i+","+j+","+classes[ideal.getInput(i, j)]);
            		bw.newLine();
            		bw.flush();
        		}
        		
            }
        }
        bw.close();
	}
	
	//damit wird ein board der größe size1xsize2 in ein anderes format gequetscht und auch das board ideal neu aufgesetzt. Notwendig um nmi werte später vernünftig zu berechnen
	public void arff2Boards(String Pfad, int size1, int size2, Board ideal) throws IOException{
		int siz1=this.size()[0];
		int siz2=this.size()[1];
		this.clear();
		ideal.clear();
		FileReader fr = new FileReader(Pfad);
	    BufferedReader br = new BufferedReader(fr);
	    String input = br.readLine();
	    double x=0;
		double y=0;
		String xa="";
		String ya="";
		String cla="";
		while(input.contains("@DATA")==false){
			input = br.readLine();
		}
		input=br.readLine();
		while (input != null){
			xa = input.substring(0,input.indexOf(","));
		    ya = input.substring(input.indexOf(",")+1,(input.length()));
		    cla = ya.substring(ya.indexOf(",")+1,ya.length());
		    ya = ya.substring(0,ya.indexOf(","));
		    x = Double.parseDouble(xa);
		    y = Double.parseDouble(ya);
		    x = x*siz1/size1;
		    y = y*siz2/size2;
		   	if(0<x && x<siz1 && 0<y && y<siz2){
		   		int i = (int) x;
		   		int j = (int) y;
		   		int k = Integer.parseInt(cla.substring(5, cla.length())); 
		    	this.getInput()[i][j]++;
		    	if(ideal.getInput(i, j)==0){
			    	ideal.setInput(i, j, k);
		    	}
		    	
		    }
		    input = br.readLine();
		}
		br.close();
		ideal.clearsingles();
	   	this.input2board();
	   	ideal.input2board();
	}
	
	public void nerv2Boards(String Pfad, int size1, int size2) throws IOException{
		int siz1=this.size()[0];
		int siz2=this.size()[1];
		this.clear();
		FileReader fr = new FileReader(Pfad);
	    BufferedReader br = new BufferedReader(fr);
	    String input = br.readLine();
	    double x=0;
		double y=0;
		String xa="";
		String ya="";
		String cla="";
		input=br.readLine();
		while (input != null){
			xa = input.substring(0,input.indexOf(","));
		    ya = input.substring(input.indexOf(",")+1,(input.length()));
		    cla = ya.substring(ya.indexOf(",")+1,ya.length());
		    ya = ya.substring(0,ya.indexOf(","));
		    x = Double.parseDouble(xa);
		    y = Double.parseDouble(ya);
		    x = x*siz1/size1;
		    y = y*siz2/size2;
		   	if(0<x && x<siz1 && 0<y && y<siz2){
		   		int i = (int) x;
		   		int j = (int) y;
		   		int k = Integer.parseInt(cla); 

			    this.setInput(i, j, k);
		    	
		    }
		    input = br.readLine();
		}
		br.close();
	   	this.input2board();
	}
	
	public ArrayList<int[]> board2data(){
		ArrayList<int[]> data = new ArrayList<int[]>();
		int size1 = this.size()[0];
		int size2 = this.size()[1];
		Board temp = new Board(size1,size2);
		temp.copy(this);
		for(int i=0;i<size1;i++){
			for(int j=0;j<size2;j++){
				while(temp.getInput(i, j)>0){
					int[] e = {i,j};
					data.add(e);
					temp.setInput(i, j, (temp.getInput(i,j)-1));
				}
			}
		}
		return data;
	}

	public void file2board(String s) throws IOException {
		FileReader fr = new FileReader(s);
	    BufferedReader br = new BufferedReader(fr);
	    String input0 = br.readLine();
	    input0=input0+"1";
	    String input;
	
        for(int i=0;i<this.size()[0];i++){
        	for(int j=0;j<this.size()[1];j++){
        		input = br.readLine();
        		int k = Integer.parseInt(input);
        		this.setInput(i, j, k);
            }
        }
        br.close();
        fr.close();
        this.input2board();
	}
	
	public void board22Ddata(String s) throws IOException{
		FileWriter fw = new FileWriter(s);
        BufferedWriter bw = new BufferedWriter(fw);
		int size1=this.size()[0];
		int size2=this.size()[1];
		Random rando = new Random();
		for(int i=0;i<size1;i++){
			for(int j=0;j<size2;j++){
				int zi = this.getInput(i, j);
				for(int k=0;k<zi;k++){
					int a = rando.nextInt(100);
					int b = rando.nextInt(100);
					bw.write(i+"."+a+","+j+"."+b);
					//bw.write(i+","+j);
			        bw.newLine();
				}
				bw.flush();
			}
		}
		bw.close();
	}
	
	//makes a board into a dataset and saves it in a txt-file
	public void board22Ddataclu(String s) throws IOException{
		FileWriter fw = new FileWriter(s);
        BufferedWriter bw = new BufferedWriter(fw);
		int size1=this.size()[0];
		int size2=this.size()[1];
		Random rando = new Random();
		for(int i=0;i<size1;i++){
			for(int j=0;j<size2;j++){
				int zi = this.getInput(i, j);
				for(int k=0;k<zi;k++){
					int a = rando.nextInt(100);
					int b = rando.nextInt(100);
					bw.write(i+"."+a+","+j+"."+b+",cla"+Levy.ideal.getInput(i, j));
					//bw.write(i+","+j);
			        bw.newLine();
				}
				bw.flush();
			}
		}
		bw.close();
	}
	
	public void sync(String s) throws IOException{
		FileReader fr = new FileReader(s+"data.txt");
		FileReader gr = new FileReader(s+"data-synC-ID.txt");
	    BufferedReader br = new BufferedReader(fr);
	    BufferedReader br2 = new BufferedReader(gr);
	    String input = br.readLine();
		String inpu = br2.readLine();
		
	    while(input!=null){
	    	String xa = input.substring(0,input.indexOf(","));
	    	String ya = input.substring(input.indexOf(",")+1,(input.length()));
	    	int x = (int) Double.parseDouble(xa);
	    	int y = (int) Double.parseDouble(ya);
	    	System.out.println(inpu);
	    	int k = (int) Double.parseDouble(inpu);
	    	System.out.println(x+", "+y+", "+k);
			System.out.println(input);
			System.out.println(inpu);
			
			input = br.readLine();
			inpu  = br2.readLine();
			this.setInput(x, y, k);
	    }
	}
	
	public void data2D2board(String s, int size1, int size2) throws IOException{
		int siz1=this.size()[0];
		int siz2=this.size()[1];
		//int[][] ba = this.getInput();
		this.clear();
		FileReader fr = new FileReader(s);
	    BufferedReader br = new BufferedReader(fr);
	    String input = br.readLine();
	    double x=0;
	    double y=0;
	    String xa="";
	    String ya="";
	    while (input != null){
	    	//System.out.println(input);
	    	xa = input.substring(0,input.indexOf(","));
	    	ya = input.substring(input.indexOf(",")+1,(input.length()));
	    	x = Double.parseDouble(xa);
	    	y = Double.parseDouble(ya);
	    	x = x*siz1/size1;
	    	y = y*siz2/size2;
	    	if(0<x && x<siz1 && 0<y && y<siz2){
	    		this.getInput()[(int) x][(int) y]++;
	    	}
	    	input = br.readLine();
	    }
	    br.close();
    	this.input2board();
	}
	
	public void file2board(String s, String t) throws IOException {
		FileReader fr = new FileReader(s);
	    BufferedReader br = new BufferedReader(fr);
	    String input0 = br.readLine();
	    input0=input0+"1";
	    String input;
	
        for(int i=0;i<Levy.size1;i++){
        	for(int j=0;j<Levy.size2;j++){
        		input = br.readLine();
        		int k = Integer.parseInt(input);
        		this.setInput(i, j, k);
            }
        }
        br.close();
        fr.close();
        this.input2board();
	}
	
	public int[] listdensities(String s){
		int size1 = this.size()[0];
		int size2 = this.size()[1];
		int[] t=new int[size1*size2];
		System.out.print(s+"={");
		int zahler = 0;
		Random rando = new Random();
		for(int i=1;i<(size1-1);i++){
			for(int j=1;j<(size2-1);j++){
				int a = this.getInput(i, j);
				//double d = rando.nextDouble();
				//d=0;
				//double c = Math.log(a+d);
				//System.out.print(c+",");
				System.out.print(a+",");
				t[zahler]=this.getInput(i, j);
				zahler++;
			}
		}
		System.out.println(this.getInput(size1-1, size2-1)+"};");
		return t;
	}
	
	public double[] listlogdensities(String s){
		int size1 = this.size()[0];
		int size2 = this.size()[1];
		double[] t=new double[size1*size2];
		System.out.print(s+"={");
		int zahler = 0;
		for(int i=1;i<(size1-1);i++){
			for(int j=1;j<(size2-1);j++){
				int a = this.getInput(i, j);
				double c=0;
				if(a>0){
					c = Math.log(a);
					System.out.print(c+",");
				}
				t[zahler]= c;
				zahler++;
			}
		}
		System.out.println(this.getInput(size1-1, size2-1)+"};");
		return t;
	}
	
	
	public void listsumy(String s){
		int size1 = this.size()[0];
		int size2 = this.size()[1];
		System.out.print(s+"={");
		for(int i=0;i<size1;i++){
			int now = 0;
			for(int j=0;j<(size2);j++){
				now = now + this.getInput(i, j);
			}
			System.out.print(now+",");
		}
		System.out.println("};");
	}
	
	public void listsumx(String s){
		int size1 = this.size()[0];
		int size2 = this.size()[1];
		System.out.print(s+"={");
		for(int i=0;i<size1;i++){
			int now = 0;
			for(int j=0;j<(size2);j++){
				now = now + this.getInput(j, i);
			}
			System.out.print(now+",");
		}
		System.out.println("};");
	}
	
	//looks up the gridcells in the clustering this that have a certain colour and adds up all the points that are entailed in this cluster in board data
	public int clustersize(int colour, Board data){
		int size=0;
		for(int i=0;i<this.size()[0];i++){
			for(int j=0;j<this.size()[1];j++){
				if(this.getInput(i, j)==colour){
					size = size+data.getInput(i, j);
				}
			}
		}
		return size;
	}
	
	//this needs to have reducecolours() had run on it
	public int[] sizeofclusters(Board data){
		int[] reto = new int[(this.boardmax()+1)];
		for(int i=0;i<reto.length;i++){
			reto[i]=this.clustersize(i, data);
		}
		return reto;
	}
	
	public double entropy(Board data){
		int points = 0;
		for(int i=0;i<this.size()[0];i++){
			for(int j=0;j<this.size()[1];j++){
				points=points+data.getInput(i, j);
			}
		}
		int N = points;
		//System.out.println(N);
		this.reducecolour();
		int max = this.boardmax();
		
		double ent = 0;
		for(int i=0;i<(max+1);i++){
			double pi = this.clustersize(i, data);
			pi=pi/N;
			ent=ent-pi*Math.log(pi);
		}
		//System.out.println(ent);
		return ent;
	}
	
	//schnittmenge von 2 clusterings berechnen
	public int[][] schnittmengen(Board clust2, Board data){
		int size1 = this.boardmax();
		int size2 = clust2.boardmax();

		int[][] schnitt = new int[size1+1][size2+1];
		
		for(int i=0;i<this.size()[0];i++){
			for(int j=0;j<this.size()[1];j++){
				int a = this.getInput(i, j);
				int b = clust2.getInput(i, j);
				schnitt[a][b]=schnitt[a][b]+data.getInput(i, j);
			}
		}
		return schnitt;
	}
	
	public double normmutinf(Board clust2, Board data){
		int points = 0;
		for(int i=0;i<this.size()[0];i++){
			for(int j=0;j<this.size()[1];j++){
				points=points+data.getInput(i, j);
			}
		}
		int N = points;
		
		this.reducecolour();
		clust2.reducecolour();
		int[][] schnitt = this.schnittmengen(clust2,data);
		
		int[] clust1size = this.sizeofclusters(data);
		int[] clust2size = clust2.sizeofclusters(data);
		double mutinf=0;
		for(int i=0;i<schnitt.length;i++){
			for(int j=0;j<schnitt[0].length;j++){
				double schnit =  schnitt[i][j];
				if(schnit!=0){
					double ui = clust1size[i];
					double vj = clust2size[j];
					double zusatz = (schnit/N)*Math.log(((N*schnit)/(ui*vj)));
					mutinf = mutinf + zusatz;
				}
			}
		}
		double hu = this.entropy(data);
		double hv = clust2.entropy(data);
		mutinf=mutinf/(Math.sqrt((hu*hv)));
		return mutinf;
	}

	public void initialize() {
		
		int[] dada = new int[5];
		for(int i=0;i<5;i++){
			Levy.data.random(10*Levy.size1*Levy.size2);
			Walk tet = new Walk(Levy.data);
			tet.jump(Levy.jump);
			Board teo = new Board(tet.getLevycount());
			dada[i]=teo.boardmax();
			Levy.data.clear();
		}
		Statistics te = new Statistics(dada);
		System.out.println((int)(te.getMean()-0*te.getStdDev()));
		Levy.grenze = (int) (te.getMean()-0*te.getStdDev());
		
		double a = Levy.size1;
		double b = Levy.size2;
		double c = Levy.jump;
		double d = c/(a*b)*0.2187;
		Board.connections =(int) (d);
	}

	public int concalc(int pospos, int startconn, int connections) {
		//int reto=startconn;
		double a = Levy.size1;
		double b = Levy.size2;
		double c = Levy.jump;
		double x = c/(a*b)*0.2187;
		x= c/(a*b)*0.2187;
		
		return (int) (x + x*(1-1000/(1000+pospos)));
	}




}
