import java.applet.Applet;
import java.awt.event.*;
import java.awt.*;
import java.awt.geom.*;


public class DyadicPlotter {
    int detail; // detail of the plot to do
    int type_of_plot;
    int mode;
    Color C;
    Complex Z;
    
    //defining functions
    int[][][] denominator=new int[3][3][1000];
    int[][] numerator=new int[4][1000];
    CombinatorialTriangle[] CT;
    int[] top;
    int[] bot;
    int palindrome;
    int spine;
    String W;
    int sign;
    VertexPair V;
    int[][] record=new int[2][2000];
    
    //lists of dyadic squares
    DyadicSquare INIT;
    DyadicSquare[] D=new DyadicSquare[200];
    DyadicSquare[] DEF=new DyadicSquare[4000];
    DyadicSquare[] IN=new DyadicSquare[4000];
    int D_N,IN_N,DEF_N;
    
    //memory
    VertexPair[] VP=new VertexPair[5000];
    Complex[][] CORNER=new Complex[3][3];
    int corner[]=new int[3];
    Complex[][] data=new Complex[3][11];
    int SMALL;
    
    //billiard like input
    Complex[] BL;
    Complex BL_CENTER;
    int right,obtuse;




    /**BASIC METHODS FOR CREATING THE PLOTTER*/

    
    /** this is a static method to do a Solid Plot all in one call. */
    public static DyadicTile SolidPlot(
    int mode, // this is the amount of rigor.
    int detail, // this is the amount of detail
    String word, // the word to plot as a string
    Color C) { // color of the tile
        DyadicPlotter DP=new DyadicPlotter(mode, 0, detail, word, C);
        return DP.doPlot();
    }
    
    /** this is a static method to do a Boxes Plot all in one call. */
    public static DyadicTile BoxesPlot(
    int mode, // this is the amount of rigor.
    int detail, // this is the amount of detail
    String word, // the word to plot as a string
    Color C) { // color of the tile
        DyadicPlotter DP=new DyadicPlotter(mode, 1, detail, word, C);
        return DP.doPlot();
    }
    
    /** this is a static method to do a Box Plot all in one call. */
    public static DyadicBoxTile BoxPlot(
    int mode, // this is the amount of rigor.
    int detail, // this is the amount of detail
    String word, // the word to plot as a string
    Color C, // color of the tile
    Complex Z){ // coordinates of triangle to box around.
        DyadicPlotter DP=new DyadicPlotter(mode, 2, detail, word, C);
        DP.Z=Z;
        return DP.doBoxPlot();
    }
    
    /** this is a static method to find the tile all in one call. */
    public static Complex FindTile(
    int mode, // this is the amount of rigor.
    int detail, // this is the amount of detail
    String word) { // the word to plot as a string
        DyadicPlotter DP=new DyadicPlotter(mode, 3, detail, word, Color.black);
        DP.doPlot();
        return DP.Z;
    }
    
    public DyadicPlotter(int mode, int type_of_plot, int detail,
    String word, Color C) {
        this.type_of_plot=type_of_plot;
        this.detail=detail;
        this.C=C;
        this.mode=mode;
        SMALL=4;
        VP[0]=new VertexPair(0,0,0,0);
        VP[0].cert=0;
        palindrome=0;
        doReset(word);
        spine=0;
        sign=1;
        corner[0]=0;
        corner[1]=0;
        corner[2]=0;
        V=new VertexPair();
    }





    /**THE MAIN ROUTINE*/

    
    // call only if type_of_plot is 0,1, or 3 (solid or boxes or find)

    public DyadicTile doPlot() {

        double time1=System.currentTimeMillis();
	DyadicPlotterInit DPI=new DyadicPlotterInit(W);
	BL=DPI.BL;
        if (BL==null) return null; // LoopWord can prove b-like tile is empty
        setBLCenter();
        initVertices();

	DPI=new DyadicPlotterInit(W);
	CORNER=DPI.CORNER;
	corner=DPI.corner;

        while(D_N>0) processSquare();
        
        if (type_of_plot==3) return null;// find doesn't care about the tile
        
        DyadicTile DT=plot();
        
        double time2=System.currentTimeMillis();
        double time=time2-time1;
        System.out.println("time: "+time);
        return DT;
    }
    
    // call only if type_of_plot is 2 (box plot)
    public DyadicBoxTile doBoxPlot() {
        double time1=System.currentTimeMillis();
	DyadicPlotterInit DPI=new DyadicPlotterInit(W);
        BL=DPI.BL;
        if (BL==null) return null;  //b-like tile empty
        setBLCenter();
        initVertices();
	CORNER=DPI.CORNER;
	corner=DPI.corner;
        while(D_N>0) processSquare();
        
        DyadicTile DT=plot();

        if (DT==null) 
            return null;
            
        DyadicBoxTile DBT=new DyadicBoxTile(DT.W, DT.P, DT.C);
        if(type_of_plot==2) { // box plot
            DBT.record=record;
            DBT.record_active=1;
            if(DEF_N>0) DBT.dyadic_size=DEF[0].k;
            if(IN_N>0) DBT.dyadic_size=IN[0].k;
        }
        
        double time2=System.currentTimeMillis();
        double time=time2-time1;
        System.out.println("time: "+time);
        return DBT;
    }
    
    
    public DyadicTile plot() {
        if(type_of_plot==0) return DyadicPlotHandler.plotSolid(W,IN,IN_N,DEF,DEF_N,CORNER,corner,C);
        else return DyadicPlotHandler.plotBoxes(W,IN,IN_N,DEF,DEF_N,CORNER,corner,C);
    }












  /** THIS IS THE INITIALIZATION PHASE*/


    public void doReset(String word) {
        int[] x={1,1};
        int[] y={1,1};
        D[0]=new DyadicSquare(x,y,0);
        INIT=new DyadicSquare(x,y,0);
        W=word;
        CT=CombinatorialTriangle.unfold(W);
        CT=CombinatorialTriangle.assignTails(CT);
        palindrome=Spine.palindromeTest(CT);
        if(awkwardWord(W)==1) palindrome=0;  //trouble with acute words starting with 12 or 21
        int qq=W.length()/2;
        if(palindrome==1) qq=W.length()/4+1;
        D[0].top=initPlayers(qq);
        D[0].bot=initPlayers(qq);
        INIT.top=initPlayers(qq);
        INIT.bot=initPlayers(qq);
        top=Spine.completeList(1,CT);
        bot=Spine.completeList(2,CT);
        D_N=1;
        IN_N=0;
        DEF_N=0;
        denominator[0]=Function.computeDenominator(0,CT);
        denominator[1]=Function.computeDenominator(1,CT);
        denominator[2]=Function.computeDenominator(2,CT);
        VP[0].cert=0;
        corner[0]=0;
        corner[1]=0;
        corner[2]=0;
    }
    


    
    public void setBLCenter() {
        Complex Z=new Complex();
        int test=0;
        for(int i=0;i<BL.length;++i) {
            Z=Complex.plus(Z,BL[i]);
            if(BL[i].x+BL[i].y==1) ++test;
        }
        right=0;
        if(test>1) right=1;
        BL_CENTER=new Complex(Z.x/BL.length,Z.y/BL.length);
        obtuse=0;
        if(BL_CENTER.x+BL_CENTER.y<1) obtuse=1;
    }
    
  
    
    /**for some reason the signs of our functions aren't
     * computed right when our word is a palindrome starting
     * with 12 or 21.  In this case, we just turn off the
     * palindromic enhancement.*/
    
    public int awkwardWord(String X) {
        int d1=1+Spine.getDigit(X,0);
        int d2=1+Spine.getDigit(X,1);
        if(d1*d2==2) return(1);
        return(0);
    }


    //these routines either do or don't use the vertices which come from
    //pat's billiard-like algorithm, depending on the mode

    public void initVertices() {
	if(mode>0) useBLVertices();
	if(mode==0) useAllVertices();
    }

    
    public void useBLVertices() {

        for(int i=0;i<INIT.top.length;++i) record[0][i]=0;
        for(int i=0;i<INIT.bot.length;++i) record[1][i]=0;
        record[0][0]=INIT.top.length;
        int[][] rel=LoopWord.relevantVertices(W);
        int count0=0;
	int count1=0;
        
        for(int i=1;i<=rel[1].length;++i) {
	    if(rel[1][i-1]<=INIT.top.length) {
	      ++count0;
              D[0].bot[count0]=rel[1][i-1];
              record[1][rel[1][i-1]]=rel[1][i-1];
	    }
        }
        D[0].bot[0]=count0;
        
        for(int i=1;i<=rel[0].length;++i) {
	    if(rel[0][i-1]<=INIT.bot.length) {
	      ++count1;
              D[0].top[count1]=rel[0][i-1];
              record[0][rel[0][i-1]]=rel[0][i-1];
	    }
        }
        D[0].top[0]=count1;
    }


    public void useAllVertices() {
        for(int i=0;i<INIT.top.length;++i) record[0][i]=i;
        for(int i=0;i<INIT.bot.length;++i) record[1][i]=i;
        record[0][0]=INIT.top.length;
    }

    
    public int[] initPlayers(int q) {
        int[] play=new int[q+1];
        play[0]=q;
        for(int i=1;i<=q;++i) play[i]=i;
        if(Spine.palindromeTest(CT)==1) play[0]=q/2+1;
        return(play);
    }


    /**END OF INITIALIZATION PHASE*/










    /**FUNCTION CREATION AND EVALUATION*/


    public int[][] getSignedNumerator(VertexPair V) {
        int[][]f=new int[0][0];
        if(palindrome==0) {
            spine=Spine.spineNumber(V,CT);
            sign=Spine.getSign(V,CT,denominator[spine]);
        }
        
        if(palindrome==1) {
            spine=Spine.spineNumber(V,CT);
            f=PalindromeFunction.getFunction(denominator[spine],V,CT);
        }
        return(f);
    }
    
    
    public int certify(VertexPair VV) {
        
        if(palindrome==1) {
            return(PalindromeFunction.certify(numerator,D[D_N-1]));
        }
        
        
        
        if(palindrome==0) {
            
            int[] a=lookup3(VV);
            if(a[0]==0) {
                if(mode<=2) a=Spine.absSecond(VV,CT,denominator[spine]);
                if(mode==3) a=Spine.cheapAbsSecond(VV,CT,denominator[spine],BL_CENTER);
                ++VP[0].cert;
                VP[VP[0].cert]=new VertexPair(VV.o1,VV.e1,VV.o2,VV.e2,a[0],a[1],a[2]); }
            int test=0;
            int test2=0;
            int gm=getMatchNumber();
            if(gm>SMALL)   test=Certify.certify(sign,VV,CT,data[spine],D[D_N-1],a);
            if(gm<=SMALL)  test=Certify.certify(sign,VV,CT,denominator[spine],D[D_N-1],a);
            return(test);
            
        }
        return(0);
    }

    
    public int signEvaluate(int cert) {
        if(palindrome==1) return(PalindromeFunction.signEvaluate(numerator,D[D_N-1],cert));
        if(palindrome==0) {
            int test=0;
            int gm=getMatchNumber();
            if(gm>SMALL) test=Spine.signEvaluate(sign,V,CT,data[spine],D[D_N-1],cert);
            if(gm<=SMALL) test=Spine.signEvaluate(sign,V,CT,denominator[spine],D[D_N-1],cert);
            return(test);
        }
        return(0);
    }
    
    
    
    
    
    
    public int crudePositiveTest(VertexPair V) {
        if(palindrome==1) return(PalindromeFunction.crudePositiveTest(numerator,D[D_N-1]));
        
        if(palindrome==0) {
            int[] a=lookup3(V);
            if(a[0]==0) {
                
                if(mode<=2) a=Spine.absSecond(V,CT,denominator[spine]);
                if(mode==3) a=Spine.cheapAbsSecond(V,CT,denominator[spine],BL_CENTER);
                ++VP[0].cert;
                VP[VP[0].cert]=new VertexPair(V.o1,V.e1,V.o2,V.e2,a[0],a[1],a[2]);
            }
            int test=0;
            int gm=getMatchNumber();
            if(gm>SMALL) test=Spine.crudePositiveTest(sign,V,CT,data[spine],D[D_N-1],a);
            if(gm<=SMALL) test=Spine.crudePositiveTest(sign,V,CT,denominator[spine],D[D_N-1],a);
            return(test);
        }
        
        return(0);
    }
    
    
    public double evaluate(Complex Z) {
        if(palindrome==0) {
            double val=Spine.evaluate(sign,V,CT,denominator[spine],Z);
            return(val);
        }
        if(palindrome==1) return(PalindromeFunction.evaluate(numerator,Z));
        return(0);
    }
    





    /**LOOKING UP STORED INFORMATION*/


    
    public int compare(VertexPair VV1,VertexPair VV2) {
        if(VV1.o1!=VV2.o1) return(0);
        if(VV1.e1!=VV2.e1) return(0);
        if(VV1.o2!=VV2.o2) return(0);
        if(VV1.e2!=VV2.e2) return(0);
        return(VV2.cert);
    }
    
    public int lookup1(VertexPair VV) {
        int N=D[D_N-1].V1[0].cert;
        int cert=0;
        for(int i=N;i>=1;--i) {
            cert=compare(VV,D[D_N-1].V1[i]);
            if(cert!=0) return(cert);
        }
        return(0);
    }


    
    public int lookup2(VertexPair V) {
        int N=D[D_N-1].V2[0].cert;
        int cert=0;
        for(int i=N;i>=1;--i) {
            cert=compare(V,D[D_N-1].V2[i]);
            if(cert!=0) return(cert);
        }
        return(0);
    }
    
    
    public int[] compare3(VertexPair VV1,VertexPair VV2) {
        int[] a=new int[3];
        a[0]=0;
        a[1]=0;
        a[2]=0;
        int test=1;
        if(VV1.o1!=VV2.o1) test=0;
        if(VV1.e1!=VV2.e1) test=0;
        if(VV1.o2!=VV2.o2) test=0;
        if(VV1.e2!=VV2.e2) test=0;
        if(test==1) {
            a[0]=VV2.a20;
            a[1]=VV2.a11;
            a[2]=VV2.a02;
        }
        return(a);
    }
    
    
    public int[] lookup3(VertexPair V) {
        int N=VP[0].cert;
        int[] a=new int[3];
        a[0]=0;
        a[1]=0;
        a[2]=0;
        for(int i=N;i>=1;--i) {
            a=compare3(V,VP[i]);
            if(a[0]!=0) return(a);
        }
        return(a);
    }
    





    
    /**STATUS OF ALGORITHM*/

    public int getMatchNumber() {
        return(D[D_N-1].top[0]*D[D_N-1].bot[0]);
    }
    






    /**HERE IS THE ALGORITHM*/

    public void processSquare() {
        int action=determineAction();
        if(action==-1) --D_N;
        if(action==0) refineList();
        if(action==1) addToInsiders();
        if(action==5) addToDefiners();
    }

    
    public void refineList() {
        DyadicSquare A=D[D_N-1];
        D[D_N-1]=DyadicSquare.subdivideAndRemember(0,0,A);
        D[D_N+0]=DyadicSquare.subdivideAndRemember(0,1,A);
        D[D_N+1]=DyadicSquare.subdivideAndRemember(1,1,A);
        D[D_N+2]=DyadicSquare.subdivideAndRemember(1,0,A);
        D_N=D_N+3;
    }
    
    
    public void addToInsiders() {
        IN[IN_N]=new DyadicSquare(D[D_N-1].x,D[D_N-1].y,D[D_N-1].k);
        ++IN_N;
        --D_N;
        //System.out.println("trying");
        if(type_of_plot==3) {
            //System.out.println("hi there");
            Z=D[D_N].getCenter(); // set Z
            D_N=0;
        }
    }
    

    public void addToDefiners() {
        DEF[DEF_N]=new DyadicSquare(D[D_N-1].x,D[D_N-1].y,D[D_N-1].k);
        DEF[DEF_N].top=new int[30];
        DEF[DEF_N].bot=new int[30];
        DEF[DEF_N].top[0]=D[D_N-1].top[0];
        DEF[DEF_N].bot[0]=D[D_N-1].bot[0];
        
        for(int i=1;i<=D[D_N-1].top[0];++i) {
            DEF[DEF_N].top[i]=D[D_N-1].top[i];
        }
        
        for(int i=1;i<=D[D_N-1].bot[0];++i) {
            DEF[DEF_N].bot[i]=D[D_N-1].bot[i];
        }
        
        ++DEF_N;
        --D_N;
    }

    

    
    public int determineAction() {
        
        if(type_of_plot==2) {
            int touch=ConvexIntersector.checkTouch(Z,D[D_N-1].toPolygon());
            if(touch==0) return(-1);
        }
        
        int test=ConvexIntersector.checkDisjoint(D[D_N-1],BL);
        if(test==3) return(-1);                    //does not intersect tile
        if(test==2) return(0);                     //contains tile
        if(D[D_N-1].k<5) return(0);                //too big
        
        
        /**only for tiles which intersect the parameter space corner*/
        
        if(corner[0]==1) {
            int test0=ConvexIntersector.checkNearCorner(D[D_N-1],CORNER[0]);   //in first corner
            if(test0==1) return(-1);
        }
        
        if(corner[1]==1) {
            int test1=ConvexIntersector.checkNearCorner(D[D_N-1],CORNER[1]);   //in second corner
            if(test1==1) return(-1);
        }
        
        if(corner[2]==1) {
            int test2=ConvexIntersector.checkNearCorner(D[D_N-1],CORNER[2]);   //in third corner
            if(test2==1) return(-1);
        }
        
        if(D[D_N-1].k>5+detail) return(-1);   //too small
        
        /**here is the tournament*/
        
        int gm=getMatchNumber();
        if(gm>SMALL) {
            data[0]=Function.assignData(denominator[0],D[D_N-1]);
            data[1]=Function.assignData(denominator[1],D[D_N-1]);
            data[2]=Function.assignData(denominator[2],D[D_N-1]);
        }

        multiRound();
        int p=0;
        if(mode<=1) p=playoffs();
        
        if(mode>1) {
            int cap=determineCap();
            if(cap==1) p=cappedPlayoffs();
            if((cap==1)&&(p==0)) p=playoffs();
            if(cap==0) p=playoffs();
        }
        /**end of the tournament*/
        
        if(p==5) return(5);
        if(p==2) return(1);
        if(p==1) return(-1);
        return(0);
    }
    
    
    public int determineCap() {
        int cap=0;
        int potential=D[D_N-1].top[0]*D[D_N-1].bot[0];
        int size=D[D_N-1].k;
        /**not sure what the right criterion is yet*/
        if((potential<=8) && (size>=detail)) cap=1;
        if((potential<=12) && (size>=detail+1)) cap=1;
        if((potential<=16) && (size>=detail+2)) cap=1;
        if((potential<=20) && (size>=detail+3)) cap=1;
        if((potential<=24) && (size>=detail+4)) cap=1;
        return(cap);
    }
    
    
    
    public int specialMatch() {
        Complex[] Z=D[D_N-1].toPolygon();
        double a0=evaluate(Z[0]);
        double a1=Math.abs(evaluate(Z[1]));
        double a3=Math.abs(evaluate(Z[3]));
        if((a1<.00000000001)&&(a3<.00000000001)) {
            if(a0<0) return(1);
            if(a0>0) return(2);
        }
        return(0);
    }
    
    
    /**here is the an individual match. First we certify the function
     * and then check its values on the current dyadic square*/
    
    
    public int doMatch(VertexPair VV) {
        int cert=0;
        int cert2=0;
        cert2=lookup1(VV);                //check record for certificate
        if(cert2>0) cert=cert2;
        numerator=getSignedNumerator(VV);
        if(cert2==0) cert=certify(VV);   //if none, then try to certify
        
        if((cert2==0)&&(cert>0)) {      //record certificate for later use
            ++D[D_N-1].V1[0].cert;
            int L=D[D_N-1].V1[0].cert;
            D[D_N-1].V1[L]=new VertexPair(VV.o1,VV.e1,VV.o2,VV.e2);
            D[D_N-1].V1[L].cert=cert;
        }

	int match=0;
	//exceptional case for families along abutting right angled line
        if((cert>0)&&(palindrome==1)&&(right==1)&&(obtuse==1)&&(rightSlop()==1)) { 
            if(V.o1*V.o2==1) match=3-match;
            if(match==2) return(2);
            if(match==1) return(1);
        }
	//regular case: do the match
        match=signEvaluate(cert);  
        if(VV.o1*VV.o2==1) match=3-match;  //in one case we swap the sign
        return(match);
    }

    /**this routine is the same as the previous one, except that
     * we're more conservative about storing certificates.  We
     * don't want the list of certificates to blow up.*/
    
    public int doPlayoffMatch(VertexPair VV) {
        
        int cert2=lookup2(VV);
        if(cert2>10) return(2);
        numerator=getSignedNumerator(VV);
        int quick=crudePositiveTest(VV);
        if(quick==1) return(2);
        
        int cert=0;
        cert2=0;
        
        if(cert2>0) cert=cert2;
        if(cert2==0) cert=certify(VV);   //if none, then try to certify
        int match=signEvaluate(cert);  //do actual match
        if(VV.o1*VV.o2==1) match=3-match;  //in one case we swap the sign
        
        if(match==2) cert=cert+10;
        
        int potential=D[D_N-1].top[0]*D[D_N-1].bot[0];
        
        if(potential<25) {
            if((cert2==0)&&(cert>0)) {      //record certificate for later use
                ++D[D_N-1].V2[0].cert;
                int L=D[D_N-1].V2[0].cert;
                D[D_N-1].V2[L]=new VertexPair(VV.o1,VV.e1,VV.o2,VV.e2);
                D[D_N-1].V2[L].cert=cert;
            }
        }
        return(match);
    }
    
    
    public int doPlayoffCert(VertexPair V) {
        int cert=0;
        int cert2=0;
        cert2=lookup2(V);                //check record for certificate
        if(cert2>0) cert=cert2;
        if(cert2==0) {
            numerator=getSignedNumerator(V);
            cert=certify(V);
        }
        if((cert2==0)&&(cert>0)) {      //record certificate for later use
            ++D[D_N-1].V2[0].cert;
            int L=D[D_N-1].V2[0].cert;
            D[D_N-1].V2[L]=new VertexPair(V.o1,V.e1,V.o2,V.e2);
            D[D_N-1].V2[L].cert=cert;
        }
        return(cert);
    }
    
    
    
    
    public void multiRound() {
        multiRound(1);
        multiRound(2);
    }
    
    
    
    public void multiRound(int q) {
        int STOP=1;
        while(STOP!=0) {
           STOP=round(q);
	}
    }
    
    public int rightSlop() {
        Complex Z=D[D_N-1].getCenter();
        if(Z.x+Z.y==1) return(1);
        return(0);
    }
    
    
    
    
    public int round(int q) {
        
        int match=0;
        int count=0;
        int previous=0;
        int elim=0;
        int BEFORE=0;
        
        if(q==1) BEFORE=D[D_N-1].top[0];
        if(q==2) BEFORE=D[D_N-1].bot[0];
        
        for(int i=1;i<BEFORE;++i) {
            
            if(q==1) {
                V.o1=1;V.e1=top[D[D_N-1].top[i+0]];
                V.o2=1;V.e2=top[D[D_N-1].top[i+1]];
            }
            
            if(q==2) {
                V.o1=2;V.e1=bot[D[D_N-1].bot[i+0]];
                V.o2=2;V.e2=bot[D[D_N-1].bot[i+1]];
            }

            

            elim=0;
            match=0;
            if(previous==2) elim=1;

            if(elim==0) {
		match=doMatch(V);
	    }


            if(match==1) elim=1;

            if((q==1)&&(match==1)) record[0][D[D_N-1].top[i]]=D[D_N-1].top[i+1];
            if((q==2)&&(match==1)) record[1][D[D_N-1].bot[i]]=D[D_N-1].bot[i+1];

            if((q==1)&&(previous==2)) record[0][D[D_N-1].top[i]]=D[D_N-1].top[i-1];
            if((q==2)&&(previous==2)) record[1][D[D_N-1].bot[i]]=D[D_N-1].bot[i-1];


            
            if(elim==0) {
                ++count;
                if(q==1) D[D_N-1].top[count]=D[D_N-1].top[i];
                if(q==2) D[D_N-1].bot[count]=D[D_N-1].bot[i];
            }
            
            previous=match;
        }
        
        //*last element*/
        if((q==1)&&(match!=2)) {++count;D[D_N-1].top[count]=D[D_N-1].top[BEFORE];}
        if((q==2)&&(match!=2)) {++count;D[D_N-1].bot[count]=D[D_N-1].bot[BEFORE];}
        
        int tlen=D[D_N-1].top[0];
        int blen=D[D_N-1].bot[0];
        if((q==1)&&(match==2)) record[0][D[D_N-1].top[tlen]]=D[D_N-1].top[tlen-1];
        if((q==2)&&(match==2)) record[1][D[D_N-1].bot[blen]]=D[D_N-1].bot[blen-1];
        
        //loop is done
        if(count==0) ++count;
        
        if(q==1) D[D_N-1].top[0]=count;
        if(q==2) D[D_N-1].bot[0]=count;
        return(BEFORE-count);
    }
    
    
    
    
    
    
    public int playoffs() {
        int match,cert;
        int fail=0;
        int potential=D[D_N-1].top[0]*D[D_N-1].bot[0];
        for(int i=1;i<=D[D_N-1].top[0];++i) {
            for(int j=1;j<=D[D_N-1].bot[0];++j) {
                V.o1=1;V.e1=top[D[D_N-1].top[i]];
                V.o2=2;V.e2=bot[D[D_N-1].bot[j]];
                match=doPlayoffMatch(V);
                if(match==0) fail=1;
                if(match==1) return(1);
            }
        }
        if(fail==1) return(0);
        return(2);
    }
    
    
    
    public int cappedPlayoffs() {
        int cert=0;
        int potential=D[D_N-1].top[0]*D[D_N-1].bot[0];
        for(int i=1;i<=D[D_N-1].top[0];++i) {
            for(int j=1;j<=D[D_N-1].bot[0];++j) {
                V.o1=1;V.e1=top[D[D_N-1].top[i]];
                V.o2=2;V.e2=bot[D[D_N-1].bot[j]];
                cert=doPlayoffCert(V);
                if(cert==0) return(0);
            }
        }
        if(potential>4) {
            int test=checkMixed();
            if(test==0) return(0);
        }
        
        return(5);
    }
    
    
    /**routines for the capped method*/
    
    public double[] getValues(VertexPair V,SmallPolygon P) {
        double[] x=new double[P.N];
        numerator=getSignedNumerator(V);
        for(int i=0;i<P.N;++i) x[i]=evaluate(P.Z[i]);
        return(x);
    }
    
    


    
    public int checkMixed(VertexPair V) {
        Complex[] PP=D[D_N-1].toPolygon();
        SmallPolygon P=new SmallPolygon(PP,4);
        double[] x=getValues(V,P);
        int neg=0;
        int pos=0;
        for(int i=0;i<4;++i) {
            if(x[i]<0) neg=1;
            if(x[i]>0) pos=1;
        }
        return(neg*pos);
    }
    
    
    
    public int checkMixed() {
        int test=0;
        for(int i=1;i<=D[D_N-1].top[0];++i) {
            for(int j=1;j<=D[D_N-1].bot[0];++j) {
                V=new VertexPair(1,top[D[D_N-1].top[i]],2,bot[D[D_N-1].bot[j]]);
                test=checkMixed(V);
                if(test==1) return(1);
            }
        }
        return(0);
    }
    
    

    
    
    /**these routines deal with tiles which potentially intersect the
     * corners of the parameter space*/
    
    public int testBelonging(Complex Z) {
        double test;
        for(int i=1;i<=INIT.top[0];++i) {
            for(int j=1;j<=INIT.bot[0];++j) {
                V=new VertexPair(1,top[INIT.top[i]],2,bot[INIT.bot[j]]);
                int spine=Spine.spineNumber(V,CT);
                numerator=getSignedNumerator(V);
                test=evaluate(Z);
                if(test<-0.0000000001) return(0); //small cutoff
            }
        }
        return(1);
    }
    
    
    
}
