import java.awt.event.*;
import java.awt.*;


public class Solver {
    int MAX,COUNT,ERROR;
    int SOLID;
    int SOLID_MAX;
    int[][] F=new int[1000][6];
    int[][] S=new int[1000][6];
    int[] INDEP;
    int[] USED;
    int[] SOL;
    int[] GUESS;
    int[] MODE=new int[4];
    int[] QUAD=new int[4];//the quad vertices
    int ANNEAL;

    public Solver() {}

    public Solver(int[][] f,int vc) {
	COUNT=vc;
	int count=0;
	for(int i=0;i<COUNT;++i) {
	    if(f[i].length==3) {
		for(int j=0;j<3;++j) {
		    F[count][j]=f[i][j];
		}
		QUAD[count]=i;
		++count;
	    }
	}
		
	for(int i=0;i<COUNT;++i) {
	    if(f[i].length==6) {
		for(int j=0;j<6;++j) {
 		    F[count][j]=f[i][j];
		}
		++count;
	    }
	}
	MAX=maxVariable();
	computeIndependent();
	ANNEAL=0;
    }


    public Solver(Solver X) {
	COUNT=X.COUNT;
	MAX=X.MAX;
	ERROR=X.ERROR;
	ANNEAL=X.ANNEAL;
	SOLID=X.SOLID;
	SOLID_MAX=X.SOLID_MAX;
	INDEP=new int[MAX+1];
	SOL=new int[MAX+1];
	USED=new int[MAX+1];
	for(int i=0;i<4;++i) MODE[i]=X.MODE[i];

	for(int i=0;i<4;++i) QUAD[i]=X.QUAD[i];
	
	for(int i=0;i<COUNT;++i) {
	    for(int j=0;j<6;++j) {
		F[i][j]=X.F[i][j];
		S[i][j]=X.S[i][j];
	    }
	}
	
	for(int i=0;i<MAX+1;++i) {
	    INDEP[i]=X.INDEP[i];
	    SOL[i]=X.SOL[i];
       	    USED[i]=X.USED[i];
	}

	if(X.GUESS==null) return;
	 int n=X.GUESS.length;
	 GUESS=new int[n];
	  for(int i=0;i<n;++i) {
	    GUESS[i]=X.GUESS[i];
	  }
    }


    public void compare(Solver SOL1,Solver SOL2) {
	for(int i=0;i<SOL1.COUNT;++i) {
	    for(int j=0;j<6;++j) {
		if(SOL1.S[i][j]!=SOL2.S[i][j]) System.out.println(i+" "+j);
	    }
	}
    }

    

	   

    public boolean isDetermined(int i,int j,int[] list) {
  	if(list[F[i][j]]>0) return true;
	return false;
    }
    

    public void computeIndependent() {
	INDEP=new int[MAX+1];
	SOL=new int[MAX+1];
	USED=new int[MAX+1];
	for(int i=0;i<MAX+1;++i) SOL[i]=-1;
	for(int i=0;i<4;++i) {
	    INDEP[F[i][0]]=1;
	    INDEP[F[i][1]]=3;
	    INDEP[F[i][2]]=3;
	}

	for(int i=4;i<COUNT;++i) {
	    for(int j=0;j<6;++j) {
		int n=numberDeterminedVariables(i);
		boolean test=isDetermined(i,j);
		if((n<5)&&(test==false)) INDEP[F[i][j]]=1;
		if((n==5)&&(test==false)) INDEP[F[i][j]]=2;
	    }
	}
    }


    public boolean isDetermined(int i,int j) {
  	if(INDEP[F[i][j]]>0) return true;
	return false;
    }

    public boolean specialVariable(int k) {
	for(int i=0;i<4;++i) {
	    for(int j=0;j<3;++j) {
		if(k==F[i][j]) return true;
	    }
	}
	return false;
    }
    

    public void assignVariables() {

	initSolution();

	for(int i=0;i<4;++i) {
	    for(int j=0;j<3;++j) {
		SOL[F[i][j]]=GUESS[i];
	    }
	}

	int count=4;
	for(int i=0;i<MAX+1;++i) {
	    boolean test=specialVariable(i);
	    if((test==false)&&(INDEP[i]==1)) {
		SOL[i]=GUESS[count];
		++count;
	    }
	}

	for(int i=4;i<COUNT;++i) {
	    for(int j=0;j<6;++j) {
		int v=currentValue(i);
		if(INDEP[F[i][j]]==2) {
		    if(USED[F[i][j]]==0) {
			SOL[F[i][j]]=(6-v)%3;
			USED[F[i][j]]=1;
		    }
		}
	    }
	}
	
	for(int i=0;i<4;++i) {
	    for(int j=0;j<3;++j) {
	    S[i][j]=SOL[F[i][j]];
	    }
	}
	for(int i=4;i<COUNT;++i) {
	    for(int j=0;j<6;++j) {
	    S[i][j]=SOL[F[i][j]];
	    }
	}
  	computeSolid();
	computeError();
    }

    public void initSolution() {
	for(int i=0;i<COUNT;++i) {
	    for(int j=0;j<6;++j) {
		S[i][j]=0;
	    }
	}
	for(int i=0;i<USED.length;++i) USED[i]=0;
	for(int i=0;i<SOL.length;++i) SOL[i]=-1;
    }

    public void computeSolid() {
  	SOLID=0;

	for(int i=4;i<COUNT;++i) {
	    int local=0;
	    for(int j=0;j<6;++j) {
		int j1=j;
		int j2=(j+1)%6;
		if(S[i][j1]!=S[i][j2]) ++local;
	    }
	    SOLID=SOLID+local;
	}
    }

    


    public void computeError() {
	ERROR=0;

	for(int i=0;i<SOL.length;++i) {
	    if(SOL[i]==0) ++ERROR;
	}

	for(int i=0;i<COUNT;++i) {
	    int v=currentValue(i);
	    if(v!=0) ++ERROR;
	}

	if(MODE[1]==1) {
	    int[] c=solCount();
	    int b=c[2]-c[1];
	    if(b<0) b=-b;
	    ERROR=ERROR+b;
	}
	
	if(MODE[2]==1) {
	    if(SOLID>SOLID_MAX) {
		ERROR=ERROR+SOLID-SOLID_MAX;
	    }
	}
    }
    

	
     public int currentValue(int i) {
	int v=0;
	for(int j=0;j<6;++j) {
	    int a=this.SOL[this.F[i][j]];
	    if(a==-1) a=0;
	    v=v+a;
	}
	v=(v+12)%3;
	return v;
    }


    public int numberDeterminedVariables(int i) {
	int count=0;
	for(int j=0;j<6;++j) {
	    if(INDEP[F[i][j]]>0) ++count;
	}
	return count;
    }

     public int maxVariable() {
	int max=0;
	for(int i=0;i<COUNT;++i) {
	    for(int j=0;j<6;++j) {
		if(max<F[i][j]) max=F[i][j];
	    }
	}
  	return max;
     }

	
    public int[] variableCount() {
	int[] count={0,0,0};
	for(int i=0;i<MAX+1;++i) {
	    int a=INDEP[i];
	    if(a==3) a=2;
	    ++count[a];
	}
	return count;
    }


    /*t has length 4*/
    
    public void initialGuess(int[] t) {
	int[] v=variableCount();
	int n=v[1];
	GUESS=new int[n];
	for(int i=0;i<4;++i) GUESS[i]=t[i]+1;
	
	for(int i=4;i<n;++i) {
	    double r=Math.random();
	    if(r<.5) GUESS[i]=1;
	    else GUESS[i]=2;
	}
	this.assignVariables();
    }

    
    public void randomChange() {
	double tol=Math.random();
	int n=GUESS.length;
	int lim=0;
	if(MODE[0]==1) lim=4;
	for(int i=lim;i<n;++i) {
	    double t=Math.random();
	    if(t<tol) GUESS[i]=3-GUESS[i];
	}
	this.assignVariables();
    }
    
    public Solver improve() {
	double a=Math.random();
	Solver SOL1=new Solver(this);
	Solver SOL2=new Solver(this);
       	SOL2.randomChange();
	
	if(SOL2.ERROR<SOL1.ERROR+ANNEAL) {
	    return SOL2;
	}
	return SOL1;
    }


    public int[] solCount() {
	int[] c={0,0,0};
	for(int i=0;i<MAX+1;++i) {
	    if(SOL[i]>-1) ++c[SOL[i]];
	}
	return c;
    }



	
    
    

    public void print(boolean elaborate) {
	System.out.println("-------------------");

	System.out.println("quad vertices");
	ListHelp.print(QUAD);
	System.out.println("flowers");
	
	for(int i=0;i<4;++i) {
	    for(int j=0;j<3;++j) {
		System.out.print(F[i][j]+"  ");
		//System.out.print(F[i][j]+":"+S[i][j]+"    ");
	    }
	    System.out.println("");
	}

	
	for(int i=4;i<COUNT;++i) {
	     int v=currentValue(i);
	    System.out.print("("+v+")  ");
	    for(int j=0;j<6;++j) {
		System.out.print(F[i][j]+"  ");
		//System.out.print(F[i][j]+":"+S[i][j]+"    ");
	    }
	    System.out.println("");
	}

	System.out.println("error "+ERROR);

	if(elaborate==true) {
	  System.out.println("variable dependency");
	  for(int i=0;i<MAX+1;++i) {
	      if(INDEP[i]==1) System.out.println(i);
	      else System.out.println("          "+i);
	  }
	}

	int[] c=solCount();
	System.out.println("red/blue "+c[1]+" "+c[2]);

    }

    public void printState() {
	ListHelp.print(GUESS);
	ListHelp.print(SOL);
    }


}

