//------------------ myPiece Class -------------------//


import java.awt.*;
import java.applet.*;
import java.io.*;
import java.lang.String;
import java.util.Random;
import java.util.Date;


public class myPiece
{
    int      myCellID[],myID,totalnum;
    boolean  exist;
    final int    RR=0,  LL=1, DD= 2,UU =3;

   public int randomise(Random nrand,int range)
	 {
	    if(range==0) return 0;
		return( java.lang.Math.abs(nrand.nextInt()) % range);
	 }
	 
private int myabs( int s0)
 {
   if(s0<0) return -s0;
    return s0;
}
	 
private  void  domySort(int SS[],int total,Random nrand)
  {
   int i,j,num=total,s0,SS2[];
   
     SS2=new int[total];
 
     for(i=0;i=1278) continue; ////////
       
       if(!gCell[id].DoGetLeftOrRightEnd()) continue;
       if(gCell[id].DoExistThisPiece(myID)) continue;
        
       return true;
   }
   
   return false;
}

private boolean   doCheckIfExistBadNB0_1(int cellID,myCell gCell[]) // edge 30
{
 int index,s0,s1;
 
   
   if(gCell[cellID].DoGetLeftOrRightEnd()) return false;
   if(!gCell[cellID].DoCheckExistNotMe(myID)) return false;
   if(!gCell[cellID].DoCheckIfExistNotOpen()) return false;
   
   index=gCell[cellID].DoGetDirNotOpen();
   
   if(index<0 || index>=3) return false; ///////
   
   s0=gCell[cellID].DoGetPieceID(index,0);
   s1=gCell[cellID].DoGetPieceID(index,1);
 
   if(s0!=myID && s1!=myID) return true;
   
   return false;
   
}
//----------------------------------------------//

private boolean   doCheckIfExistBadNB(int cellID,myCell gCell[])//  Edge sukima
{
 int index,id;
 
   if(gCell[cellID].DoGetLeftOrRightEnd()) return false;
   if(!gCell[cellID].DoCheckIfExistEmpty()) return false;
   if(!gCell[cellID].DoCheckIfExistNotOpen()) return false;

   index=gCell[cellID].DoGetDirNotExistPiece();
   if(index==-1) return false; //{ myAlert(200,"\pError 10"); return false;}

   id=gCell[cellID].DoGetDoorNBID(index,0);
   if(gCell[id].DoCheckIfExistSomething()) return true;
    
    return false;
   
}

private boolean   doCheckIfExistBadNB2(int cellID,myCell gCell[],myCellUtility cellU)//  Single Island (Me)
{
 int i,id,num=0,dstid[],val=0;
 
    dstid=new int[2];
 
   if(!gCell[cellID].DoCheckIfExistEmpty()) return false;
 
   for(i=0;i<3;i++){
      if(!gCell[cellID].DoGetOpen(i)) continue;
      id=gCell[cellID].DoGetDoorNBID(i,0);
      if(cellU.CL_DoCheckIfExistEmptyToThisDirection(id,cellID,gCell)) {  ///////// 
         num++;
         dstid[0]=id;
         dstid[1]=gCell[id].DoGetDoorNBID(i,1);
         val=i;
      }
   }
   if(num==0) return true;
   if(num>1) return false;
   
   if(gCell[cellID].DoGetPieceID(val,0)!=-1 ||
      gCell[cellID].DoGetPieceID(val,1)!=-1 ) return true;
   
   if(gCell[dstid[0]].DoGetPieceID(dstid[1],0)==-1 && 
      gCell[dstid[0]].DoGetPieceID(dstid[1],1)==-1) return false;
      
   return true;
        
}

private boolean   doCheckIfExistBadNB3(int cellID,myCell gCell[],myCellUtility cellU)//  Single Island (not Me)
{
 int i,id;
 
   if(gCell[cellID].DoCheckIfExistEmpty()) return false;
 
   for(i=0;i<3;i++){
      if(!gCell[cellID].DoGetOpen(i)) continue;
      id=gCell[cellID].DoGetDoorNBID(i,0);
      if(gCell[id].DoCheckIfExistEmpty()) 
           if(doCheckIfExistBadNB2(id,gCell,cellU)) return true;
   }
   
   return false;
}

private boolean   doCheckIfExistBadNB4(int cellID,myCell gCell[],myCellUtility cellU)//  Edge sukima2
{
 int id,s0,i,dst=0;
 
      if(!gCell[cellID].DoGetIfEdge()) return false;
      if(!gCell[cellID].DoCheckIfExistEmpty())  return false;
      
      s0=gCell[cellID].DoGetDirNotOpen();
      if(s0<0 || s0>=3) return false; ///
      
      if(gCell[cellID].DoGetPieceID(s0,0)!=-1 && 
         gCell[cellID].DoGetPieceID(s0,1)!=-1 ) return false;
         
      s0=cellU.PC_DoGetEdgeCellID2(cellID);
      s0--; if(s0<0) s0=90;
      id=cellU.PC_DoGetEdgeCellID(s0);
      if(id<0 || id>=1278) return false; ///
         
      for(i=0;i<3;i++){
        if(!gCell[cellID].DoGetOpen(i)) continue;
        s0=gCell[cellID].DoGetDoorNBID(i,0);
        if(s0<0 || s0>=1278) continue; ///// 7/9
        if(gCell[s0].DoExistThisNextCell(id)){
          dst=i; break;
        }
     }
     
    if(dst<0 || dst>=3) return false; // 7/9
   
    if(gCell[cellID].DoGetPieceID(dst,0)!=-1 &&
       gCell[cellID].DoGetPieceID(dst,1)!=-1 ) return false;
       
    return true;
    
}

private boolean   doCheckIfExistBadNB5(int cellID,myCell gCell[])// small  rectangle
{
 int i,id,val,s0,s1;
 
     if(!gCell[cellID].DoCheckIfExistEmpty())  return false;
   
     for(i=0;i<3;i++){
        if(!gCell[cellID].DoGetOpen(i)) continue;
        id=gCell[cellID].DoGetDoorNBID(i,0);
        if(!gCell[cellID].DoCheckIfExistEmpty()) continue;
           
         val=gCell[cellID].DoGetDoorNBID(i,1);
       
        //----------------------------------------------//
        if(gCell[cellID].DoGetPieceID(i,0)==-1 &&
           gCell[cellID].DoGetPieceID(i,1)==-1 ) {
           
            if(gCell[id].DoGetPieceID(val,0)==-1 && 
               gCell[id].DoGetPieceID(val,1)==-1 ) {
             
                s0=gCell[cellID].DoGetDirExistNotExist();
                s1=gCell[id].DoGetDirExistNotExist();
                if((s0==LL && s1==RR) || (s0==RR && s1==LL) || (s0==UU && s1==DD) ||  (s0==DD && s1==UU)) return true;
            
             }else if((gCell[id].DoGetPieceID(val,0)==-1 && gCell[id].DoGetPieceID(val,1)!=-1) ||
                      (gCell[id].DoGetPieceID(val,0)!=-1 && gCell[id].DoGetPieceID(val,1)==-1)){
                   return true;
             }
        }//---------------------------------------------//
        else if((gCell[cellID].DoGetPieceID(i,0)==-1 &&  gCell[cellID].DoGetPieceID(i,1)!=-1) || 
                (gCell[cellID].DoGetPieceID(i,0)!=-1 &&  gCell[cellID].DoGetPieceID(i,1)==-1)){
         
             if(gCell[id].DoGetPieceID(val,0)==-1 && gCell[id].DoGetPieceID(val,1)==-1 )  return true;
        }//-------------------------------------------------------------//
         
     }
     
    return false;

}

private boolean   doCheckIfExistBadNB6(int cellID,myCell gCell[],myCellUtility cellU)// 2 island (me)
{
 int s0,s1,dst,val,dst2,ss[],temp[],num;
 
   ss  =new int[3];
   temp=new int[3];
 
    if(!gCell[cellID].DoCheckIfExistEmpty())  return false;
 
     num=cellU.CL_DoGetOpenDirectionNum(cellID,ss,gCell);
     if(num==0) return true;
     if(num!=1 && num!=2) return false;

     if(num==1){
      int ss2[];
        ss2=new int[3]; //////
        dst=ss[0];
        s0=cellU.CL_DoGetOpenDirectionNum(dst,ss2,gCell);
        if(s0==1) return true;
        if(s0==3) return false;
     }else{
     
        s0=cellU.CL_DoGetOpenDirectionNum(ss[0],temp,gCell);
        s1=cellU.CL_DoGetOpenDirectionNum(ss[1],temp,gCell);
        if(s0==1 && s1==1) return true;
        
        dst=cellID;
        if(s0==1 && s1==2)      cellID=ss[0];
        else if(s0==2 && s1==1) cellID=ss[1];
        else  return false;
     }
     
     val=cellU.CL_DoGetOpenDirectionNotThis(dst,cellID,gCell);
     if(val==-1) return false; //{ myAlert(200,"\pError NB6"); return false;}
     
     if(gCell[dst].DoGetLeftOrRightEnd())   return true;
     else if(gCell[dst].DoCheckIfExistSomething()) return true;
      
     dst2=gCell[dst].DoGetDoorNBID(val,0);
     s0  =gCell[dst].DoGetDoorNBID(val,1);
     
     s0=cellU.CL_DoGetExistEmptyDirectionNum(dst2,s0,gCell);
     if(s0==1) return true;
     
     return false;

}

private boolean   doCheckIfExistBadNB7(int cellID,myCell gCell[],myCellUtility cellU)// 2 island (not me)
{
 int i,id;
 
   if(gCell[cellID].DoCheckIfExistEmpty()) return false;
 
    for(i=0;i<3;i++){
       if(!gCell[cellID].DoGetOpen(i)) continue;
       id=gCell[cellID].DoGetDoorNBID(i,0);
       if(id==cellID) continue;
       
       if(id<0 || id>=1278) continue; /// 7/9
       if(gCell[id].DoCheckIfExistEmpty())  { if(doCheckIfExistBadNB6(id,gCell,cellU)) return true;}
    }

    return false;
}

//----------------------------- Contact Edge ---------------------------------------//


public boolean     DoContactEdge(Random nrand,myPieceTypeClass gPieceType[],myCell gCell[],myCellUtility cellU,myTypeUtility typeU)
{
 int          id,i,count=0,ss[];
 boolean      ok,done=false;
 myPieceType  type=new myPieceType();
 
     ss=new int[6];
 
     totalnum=gPieceType[myID].totalnum;
      
     while(!done){
     
     for(i=0;i<12;i++) myCellID[i]=-1;
 
     id= cellU.PC_DoGetEdgeCellID(randomise(nrand,90));
   
     if(randomise(nrand,2)==1){
     
        domySort(ss,6,nrand);//
        for(i=0;i<6;i++){
         // type=gPieceType[myID].mytype[ss[i]];
          ok=DoContactThisType(gPieceType[myID].mytype[ss[i]],id,gCell,cellU,typeU,nrand);
          if(ok) { exist=true; return true;}
        }
     
        domySort(ss,6,nrand);//
        for(i=0;i<6;i++){
         // type=gPieceType[myID].mytype[ss[i]];
          typeU.TP_DomyCopyType(gPieceType[myID].mytype[ss[i]],type);
          typeU.TP_DoCreateInvertType(type,totalnum);
          ok=DoContactThisType(type,id,gCell,cellU,typeU,nrand);
          if(ok) { exist=true;  return true; }
        }
        
      }else {
      
        domySort(ss,6,nrand);//
        for(i=0;i<6;i++){
         // type=gPieceType[myID].mytype[ss[i]];
          typeU.TP_DomyCopyType(gPieceType[myID].mytype[ss[i]],type);
          typeU.TP_DoCreateInvertType(type,totalnum);
          ok=DoContactThisType(type,id,gCell,cellU,typeU,nrand);
          if(ok) { exist=true; return true;  }
        }
      
         domySort(ss,6,nrand);//
         for(i=0;i<6;i++){
          //type=gPieceType[myID].mytype[ss[i]];
          ok=DoContactThisType(gPieceType[myID].mytype[ss[i]],id,gCell,cellU,typeU,nrand);
          if(ok){ exist=true; return true;}
        }
      }
      
       count ++;   if(count>500) done=true;
    }
    
    return false;
    
}

public boolean  DoContactThisType(myPieceType type,int cellid,myCell gCell[],myCellUtility cellU,myTypeUtility typeU,Random nrand)
{
 int       i,j,id,ss[];
 myPoint   p0=new myPoint(),p1=new myPoint();
 boolean   ok;
 
     ss=new int[12];
 
     domySort(ss,totalnum,nrand);//
 
     for(i=0;iDoSetOldPieceID(); //
    //   gCell[id]->DoGetOldPieceID(oldCellID); // 7/2
   
      if(type.full[i]){
          myCellID[s0]=id;
          myCellID[s0+1]=id;
          s0 +=2;
          
          gCell[id].DoSetPieceIDAll(myID);
      }else {
          myCellID[s0]=id;
          s0 ++;
          
          gCell[id].DoSetPieceIDbyType(myID,type.halfindex[i]);
      }
   }
 
}

//---------------------- Contact Next -------------------------//

public boolean      DoContactNext(int id,Random nrand,myPieceTypeClass gPieceType[],myCell gCell[],myCellUtility cellU,myTypeUtility typeU)
{
 int          i,ss[];// id
 boolean      ok;
 myPieceType  type=new myPieceType();
 
     ss=new int[6];
 
     for(i=0;i<12;i++) myCellID[i]=-1;
  
    // id=cellU.PC_DoGetNextEdgeCell(preID,gCell);
 
     totalnum=gPieceType[myID].totalnum;
   
     if(randomise(nrand,2)==1){
     
        domySort(ss,6,nrand);//
        for(i=0;i<6;i++){
         // type=gPieceType[myID].mytype[ss[i]];
          ok=DoContactThisType2(gPieceType[myID].mytype[ss[i]],id,nrand,gCell,cellU,typeU);
          if(ok) { exist=true; return true;}
        }
     
        domySort(ss,6,nrand);//
        for(i=0;i<6;i++){
        //  type=gPieceType[myID].mytype[ss[i]];
          typeU.TP_DomyCopyType(gPieceType[myID].mytype[ss[i]],type);
          typeU.TP_DoCreateInvertType(type,totalnum);
          ok=DoContactThisType2(type,id,nrand,gCell,cellU,typeU);
          if(ok) { exist=true;  return true; }
        }
        
      }else {
      
        domySort(ss,6,nrand);//
        for(i=0;i<6;i++){
         // type=gPieceType[myID].mytype[ss[i]];
          typeU.TP_DomyCopyType(gPieceType[myID].mytype[ss[i]],type);
          typeU.TP_DoCreateInvertType(type,totalnum);
          ok=DoContactThisType2(type,id,nrand,gCell,cellU,typeU);
          if(ok) { exist=true; return true;  }
        }
      
         domySort(ss,6,nrand);//
         for(i=0;i<6;i++){
         // type=gPieceType[myID].mytype[ss[i]];
          ok=DoContactThisType2(gPieceType[myID].mytype[ss[i]],id,nrand,gCell,cellU,typeU);
          if(ok){ exist=true; return true;}
        }
      }
    
    return false;

}


private boolean  DoContactThisType2(myPieceType type,int cellid,Random nrand,myCell gCell[],myCellUtility cellU,myTypeUtility typeU)
{
 int       i,j,id,ss[];
 myPoint   p0=new myPoint(),p1=new myPoint();
 boolean   ok;
 
      ss=new int[12];
 
      domySort(ss,totalnum,nrand);//
 
     for(i=0;iDoSetOldPieceID(); //
      // gCell[id]->DoGetOldPieceID(oldCellID); // 7/2
   
      if(type.full[i]){
      
         if(gCell[id].DoCheckIfExistSomething()) return false; //////
         
          myCellID[s0]=id;
          myCellID[s0+1]=id;
          s0 +=2;
          
          gCell[id].DoSetPieceIDAll(myID);
      }else {
         
          if(!gCell[id].DoCheckIfExistHalfEmptybyType(type.halfindex[i])) return false;
        
          myCellID[s0]=id;
          s0 ++;
          
          gCell[id].DoSetPieceIDbyType(myID,type.halfindex[i]);
      }
   }
 
  return true;
 
}

//-------------------------------------------------------------//


public void  DoReDrawFrame(Graphics G,myCell gCell[],int offset)
{
 int i,k,xx[],yy[],num,ss[],myN,sx[][],sy[][];
 boolean ok,done,bb[];
 
    if(!exist) return;
 
    xx=new int[36];
    yy=new int[36];
    ss=new int[12];
    sx=new int[12][3];
    sy=new int[12][3];
    bb=new boolean[12];
    
    ss[0]=myCellID[0];
    myN=1;
    
    for(i=1;i<12;i++){
       ok=true;
       for(k=0;knum){ 
               bb[i]=true;  num=newN;   ok=false;
               num=doEliminateLoop(xx,yy,num);
               num=doEliminateLoop(xx,yy,num); //
               num=doEliminateLoop(xx,yy,num); // 
               num=doEliminateLoop2(xx,yy,num); // 
           }
        }
       
       if(ok) done=true;
    }
  
   for(i=0;i=3) s1=0;
     
     for(k=0;k=num) ss1=0;
        
        if(donear(sx[s0],sy[s0],xx[ss1],yy[ss1]) &&
           donear(sx[s1],sy[s1],xx[ss0],yy[ss0])){//------------//
            
            switch(i){
               case 0: id=2; break;
               case 1: id=0; break;
               case 2: id=1; break;
            }
           
          if(k==num-1){
              xx[num]=sx[id]; yy[num]=sy[id];  
           }else {
             
             for(j=num;j>=ss1+1;j--){
               xx[j]=xx[j-1];
               yy[j]=yy[j-1];
              }
                xx[ss1]=sx[id];
                yy[ss1]=sy[id];
           }
           
           num++;
           
           return num;
           
        }//----------------------------------------//
      
     }
  }
  
  //------------------------------------------------//
  
   for(i=0;i<3;i++){
     int s0,s1;
     
     s0=i;
     s1=i+1; if(s1>=3) s1=0;
     
     for(k=0;k=num) ss1=0;
        
        if(donear(sx[s0],sy[s0],xx[ss1],yy[ss1]) &&
           donear(sx[s1],sy[s1],(xx[ss0]+xx[ss1])/2, (yy[ss0]+yy[ss1])/2)){
        
          if(k==num-1){
            xx[num]=sx[s1];
            yy[num]=sy[s1];
            xx[num+1]=sx[(s1+1) % 3]; 
            yy[num+1]=sy[(s1+1) % 3];
          }else {
          
             for(j=num+1;j>=ss1+2;j--){
               xx[j]=xx[j-2];
               yy[j]=yy[j-2];
              }
                xx[ss1+1]=sx[(s1+1) % 3];
                yy[ss1+1]=sy[(s1+1) % 3];
                xx[ss1]=sx[s1];
                yy[ss1]=sy[s1];
           }
        
           return num+2;
        }
        
        //------------------------------------------------//
          
        if(donear(sx[s1],sy[s1],xx[ss0],yy[ss0]) &&
           donear(sx[s0],sy[s0],(xx[ss0]+xx[ss1])/2, (yy[ss0]+yy[ss1])/2)){
        
          if(k==num-1){
            xx[num]=sx[(s1+1) % 3]; yy[num]=sy[(s1+1) % 3];
            xx[num+1]=sx[s0]; 
            yy[num+1]=sy[s0];
          }else {
          
             for(j=num+1;j>=ss1+2;j--){
               xx[j]=xx[j-2];
               yy[j]=yy[j-2];
              }
                xx[ss1+1]=sx[s0];
                yy[ss1+1]=sy[s0];
                xx[ss1]=sx[(s1+1) % 3];
                yy[ss1]=sy[(s1+1) % 3];
           }
        
           return num+2;
        }
     
     }
  }
  
  //---------------------------------------//
  
  
   for(i=0;i<3;i++){
     int s0,s1;
     
     s0=i;
     s1=i+1; if(s1>=3) s1=0;
     
     for(k=0;k=num) ss1=0;
        
        if(donear(sx[s1],sy[s1],xx[ss0],yy[ss0]) &&
           donear((sx[s0]+sx[s1])/2,(sy[s0]+sy[s1])/2,xx[ss1],yy[ss1])){
        
          if(k==num-1){
            xx[num]=sx[(s1+1) % 3];
            yy[num]=sy[(s1+1) % 3];
            xx[num+1]=sx[s0]; 
            yy[num+1]=sy[s0];
          }else {
          
             for(j=num+1;j>=ss1+2;j--){
               xx[j]=xx[j-2];
               yy[j]=yy[j-2];
              }
                xx[ss1+1]=sx[s0];
                yy[ss1+1]=sy[s0];
                xx[ss1]=sx[(s1+1) % 3];
                yy[ss1]=sy[(s1+1) % 3];
           }
        
           return num+2;
        }
        
        //------------------------------------------------//
          
        if(donear(sx[s0],sy[s0],xx[ss1],yy[ss1]) &&
           donear((sx[s0]+sx[s1])/2,(sy[s0]+sy[s1])/2,xx[ss0],yy[ss0])){
        
          if(k==num-1){
            xx[num]=sx[s1]; 
            yy[num]=sy[s1];
            xx[num+1]=sx[(s1+1) % 3]; 
            yy[num+1]=sy[(s1+1) % 3];
          }else {
          
              for(j=num+1;j>=ss1+2;j--){
                xx[j]=xx[j-2];
                yy[j]=yy[j-2];
              }
                xx[ss1+1]=sx[(s1+1) % 3];
                yy[ss1+1]=sy[(s1+1) % 3];
                xx[ss1]=sx[s1];
                yy[ss1]=sy[s1];
           }
        
           return num+2;
        }
     
     }
  }
  

   return num;

}

private int   doEliminateLoop(int xx[],int yy[],int num)
{
 int i,s0,s1,k;
 
   for(i=0;i< num-1;i++){
     s0=i;
     s1=(i+2) % num;
     
     if(donear(xx[s0],yy[s0],xx[s1],yy[s1])){
     
        if(s1==0) return num-2;
        else if(s1==1){
        
          for(k=0;k< num-2;k++){
            xx[k]=xx[k+1];
            yy[k]=yy[k+1];
          }
           return num-2;
        
        }else {
        
          for(k=s0+1;k<=num-3;k++) {
            xx[k]=xx[k+2];
            yy[k]=yy[k+2];
          }
          return num-2;
        }
     }
   
   }

   return num;

}


private int   doEliminateLoop2(int xx[],int yy[],int num)
{
 int i,s0,s1,s2,k;
 
   for(i=0;i< num-1;i++){
     s0=i;
     s1=(i+1) % num;
     s2=(i+2) % num;
     
     if(donear(xx[s0],yy[s0],(xx[s1]+xx[s2])/2,(yy[s1]+yy[s2])/2)){
     
        if(s1==num-1) return num-1;
        else  if(s1==0){
            xx[0]=xx[s0];
            yy[0]=yy[s0];
            return num-1;
        }else {
        
          for(k=s1;k<=num-2;k++) {
            xx[k]=xx[k+1];
            yy[k]=yy[k+1];
          }
          return num-1;
        }
     }//-------------------------------//
     
      if(donear(xx[s2],yy[s2],(xx[s1]+xx[s0])/2,(yy[s1]+yy[s0])/2)){
     
        if(s1==num-1) return num-1;
        else  if(s1==0){
            xx[0]=xx[s2];
            yy[0]=yy[s2];
            return num-1;
        }else {
        
          for(k=s1;k<=num-2;k++) {
            xx[k]=xx[k+1];
            yy[k]=yy[k+1];
          }
          return num-1;
        }
     }
   
   }

   return num;

}


private boolean   donear(int x0,int y0,int x1,int y1)
{

  if(myabs(x0-x1)<=2 && myabs(y0-y1)<=2) return true;
  return false;
}

}