import java.awt.*;
import java.awt.event.*;
import java.applet.*;
////////////////////////////////////////////////////////////////////////

public class applsudo extends Applet{
int xclose=310,yclose=10;
int dclose=10;



int xgrid=20,ygrid=30;
int dgrid=28;


int xgener=295,ygener=10;
int dxgener=55,dygener=20;


int xgenerhard=300,ygenerhard=35;
int dxgenerhard=40,dygenerhard=20;

int xgenereasy=300,ygenereasy=60;
int dxgenereasy=40,dygenereasy=20;


int xrezolva=300,yrezolva=85;
int dxrezolva=40,dyrezolva=20;

int xhint=300,yhint=110;
int dxhint=40,dyhint=20;

int xskimm=300,yskimm=135;
int dxskimm=40,dyskimm=20;

int xrestart=295,yrestart=170;
int dxrestart=50,dyrestart=20;

int xsterge=300,ysterge=195;
int dxsterge=40,dysterge=20;

int xsave=300,ysave=220;
int dxsave=40,dysave=20;

int xload=300,yload=245;
int dxload=40,dyload=20;


int xcsv=300,ycsv=270;
int dxcsv=40,dycsv=20;

int textoffs=4;
int vals[][];
int salvals[][];
int restartvals[][];
sudoku mysudoku;

randomThread threadrandom;
hardrandomThread threadhardrandom;
easyrandomThread threadeasyrandom;
hintThread threadhint;
skimThread threadskim;
solveThread threadsolve;


////////////////////////////////////////////////////////////////////////

public void init()
{
addMouseListener(new MouseAdapterinWindow());
aloc_mems();
init_vals();
}
void close_window(){
//System.exit(0);
}

////////////////////////////////////////////////////////////////////////
public void aloc_mems()
{
vals=new int[9][9];
salvals=new int[9][9];
restartvals=new int[9][9];
mysudoku=new sudoku();
}

public void init_vals()
{
zero_matr();
zero_salv();
zero_salv_restart();
}

public void zero_matr()
{int i,j;
for(i=0;i<9;i++)
for(j=0;j<9;j++)
vals[i][j]=0;
}

public void zero_salv()
{int i,j;
for(i=0;i<9;i++)
for(j=0;j<9;j++)
salvals[i][j]=0;
}

public void zero_salv_restart()
{int i,j;
for(i=0;i<9;i++)
for(j=0;j<9;j++)
restartvals[i][j]=0;
}

public void salv_matr()
{int i,j;
for(i=0;i<9;i++)
for(j=0;j<9;j++)
salvals[i][j]=vals[i][j];
}

public void restore_matr()
{int i,j;
for(i=0;i<9;i++)
for(j=0;j<9;j++)
vals[i][j]=salvals[i][j];
}


public void salv_matr_restart()
{int i,j;
for(i=0;i<9;i++)
for(j=0;j<9;j++)
restartvals[i][j]=vals[i][j];
}

public void restore_matr_restart()
{int i,j;
for(i=0;i<9;i++)
for(j=0;j<9;j++)
vals[i][j]=restartvals[i][j];
}

void inc_val_mat(int i,int j)
{int val;
val=vals[i][j];
val++;
if(val==10)val=0;
vals[i][j]=val;
}

void dec_val_mat(int i,int j)
{int val;
val=vals[i][j];
val--;
if(val==-1)val=9;
vals[i][j]=val;
}


////////////////////////////////////////////////////////////////////////
boolean is_working()
{
if(threadrandom!=null)
if(threadrandom.isAlive())return true;
if(threadhardrandom!=null)
if(threadhardrandom.isAlive())return true;
if(threadeasyrandom!=null)
if(threadeasyrandom.isAlive())return true;
if(threadhint!=null)
if(threadhint.isAlive())return true;
if(threadskim!=null)
if(threadskim.isAlive())return true;
if(threadsolve!=null)
if(threadsolve.isAlive())return true;
return false;
}

void getposs(int i,int j,int[] ret)
{
ret[1]=ygrid+dgrid/2+i*dgrid;
ret[0]=xgrid+dgrid/2+j*dgrid;
}
  public static int roundint(double x) {
if(x<0)
return (int)(x-0.5);
else
return (int)(x+0.5);
}

////////////////////////////////////////////////////////////////////////
class MouseAdapterinWindow extends MouseAdapter{

public void mouseClicked(MouseEvent e){
int x,y;
int but;
int cex,cey;
int ret[];

if(is_working())return;

x=e.getX();y=e.getY();
but=e.getButton();

if(is_inclose(x,y))
     {
     close_window();
	 return;
     }
if(is_inrezolva(x,y))
     {
     threadsolve=new solveThread();
     threadsolve.start();
	 return;
     }
if(is_insterge(x,y))
     {
	zero_matr();
	repaint();
	return;
     }
if(is_inrestart(x,y))
     {
	restore_matr_restart();
	repaint();
	return;
     }
if(is_ingener(x,y))
     {
     threadrandom=new randomThread();
     threadrandom.start();
     return;
     }
if(is_ingenerhard(x,y))
     {
     threadhardrandom=new hardrandomThread();
     threadhardrandom.start();
     return;
     }
if(is_ingenereasy(x,y))
     {
     threadeasyrandom=new easyrandomThread();
     threadeasyrandom.start();
     return;
     }
if(is_inhint(x,y))
     {
     threadhint=new hintThread();
     threadhint.start();
     return;
     }
if(is_insalv(x,y))
     {
	salv_matr();
	return;
     }
if(is_inload(x,y))
     {
	restore_matr();
	repaint();
	return;
     }
if(is_inskimm(x,y))
     {
     threadskim=new skimThread();
     threadskim.start();
     return;
     }

if(is_incsv(x,y))
     {
	print_vals();
     return;
     }

ret=getposxy(x,y);
if(ret!=null)
{
if(but==1)
inc_val_mat(ret[0],ret[1]);
else
dec_val_mat(ret[0],ret[1]);
repa(ret[0],ret[1]);
}

}

}


////////////////////////////////////////////////////////////////////////

  public void paint(Graphics g) {

//draw_close_butt(g);
//draw_grid(g);
draw_linesgrid(g);
paint_matr(g);
draw_sign_rezolva(g);
draw_sign_sterge(g);
draw_sign_gener(g);
draw_sign_generhard(g);
draw_sign_genereasy(g);
draw_sign_hint(g);
draw_sign_save(g);
draw_sign_load(g);
draw_sign_skimm(g);
draw_sign_restart(g);
draw_sign_csv(g);
//draw_state(g);
      super.paint(g);
  }
void draw_close_butt(Graphics g)
{
g.drawRect(xclose,yclose,dclose,dclose);
//diags
g.drawLine(xclose,yclose,xclose+dclose,yclose+dclose);
g.drawLine(xclose+dclose,yclose,xclose,yclose+dclose);
}

void draw_grid(Graphics g)
{int i,j;
int vect[]=new int[2];
int dim=dgrid-2;
int jumdim=dim/2;
for(i=0;i<9;i++)
for(j=0;j<9;j++)
{
getposs(i,j,vect);
g.drawRect(vect[0]-jumdim,vect[1]-jumdim,dim,dim);
}
}

void draw_linesgrid(Graphics g)
{int k;
int vect[]=new int[2];
int jumdgrid=dgrid/2;

int startx,starty,endx,endy;

for(k=0;k<=9;k++)
{
getposs(0,k,vect);startx=vect[0]-jumdgrid;starty=vect[1]-jumdgrid;
getposs(9,k,vect);endx=vect[0]-jumdgrid;endy=vect[1]-jumdgrid;
g.drawLine(startx,starty,endx,endy);

getposs(k,0,vect);startx=vect[0]-jumdgrid;starty=vect[1]-jumdgrid;
getposs(k,9,vect);endx=vect[0]-jumdgrid;endy=vect[1]-jumdgrid;
g.drawLine(startx,starty,endx,endy);
}

for(k=0;k<=3;k++)
{
getposs(0,3*k,vect);startx=vect[0]-jumdgrid;starty=vect[1]-jumdgrid;
getposs(9,3*k,vect);endx=vect[0]-jumdgrid;endy=vect[1]-jumdgrid;
g.drawLine(startx-1,starty,endx-1,endy);
g.drawLine(startx+1,starty,endx+1,endy);

getposs(3*k,0,vect);startx=vect[0]-jumdgrid;starty=vect[1]-jumdgrid;
getposs(3*k,9,vect);endx=vect[0]-jumdgrid;endy=vect[1]-jumdgrid;
g.drawLine(startx,starty-1,endx,endy-1);
g.drawLine(startx,starty+1,endx,endy+1);
}

}


void paint_matr(Graphics g)
{int i,j;
int[] vect=new int[2];
char chars[];
int jumdgrid=dgrid/2-4;

chars=new char[1];
for(i=0;i<9;i++)
for(j=0;j<9;j++)
{
getposs(i,j,vect);

if(vals[i][j]!=0)
chars[0]=(char)(48+vals[i][j]);
else
chars[0]=(char)(32);

g.drawChars(chars,0,1,vect[0]-2,vect[1]+jumdgrid-4);
}
}

void draw_sign_rezolva(Graphics g)
{
char chars[];

chars=new char[5];
g.drawRect(xrezolva,yrezolva,dxrezolva,dyrezolva);

chars[0]='S';
chars[1]='o';
chars[2]='l';
chars[3]='v';
chars[4]='e';
g.drawChars(chars,0,5,xrezolva+textoffs,yrezolva+dyrezolva/2+textoffs);
}

void draw_sign_sterge(Graphics g)
{
char chars[];

chars=new char[5];
g.drawRect(xsterge,ysterge,dxsterge,dysterge);

chars[0]='C';
chars[1]='l';
chars[2]='e';
chars[3]='a';
chars[4]='r';
g.drawChars(chars,0,5,xsterge+textoffs,ysterge+dysterge/2+textoffs);
}

void draw_sign_gener(Graphics g)
{
char chars[];

chars=new char[6];
g.drawRect(xgener,ygener,dxgener,dygener);

chars[0]='R';
chars[1]='a';
chars[2]='n';
chars[3]='d';
chars[4]='o';
chars[5]='m';
g.drawChars(chars,0,6,xgener+textoffs,ygener+dygener/2+textoffs);
}

void draw_sign_generhard(Graphics g)
{
char chars[];

chars=new char[5];
g.drawRect(xgenerhard,ygenerhard,dxgenerhard,dygenerhard);

chars[0]='H';
chars[1]='a';
chars[2]='r';
chars[3]='d';
chars[4]='!';
g.drawChars(chars,0,5,xgenerhard+textoffs,ygenerhard+dygenerhard/2+textoffs);
}

void draw_sign_genereasy(Graphics g)
{
char chars[];

chars=new char[5];
g.drawRect(xgenereasy,ygenereasy,dxgenereasy,dygenereasy);

chars[0]='E';
chars[1]='a';
chars[2]='s';
chars[3]='y';
chars[4]='.';
g.drawChars(chars,0,5,xgenereasy+textoffs,ygenereasy+dygenereasy/2+textoffs);
}

void draw_sign_hint(Graphics g)
{
char chars[];

chars=new char[4];
g.drawRect(xhint,yhint,dxhint,dyhint);

chars[0]='H';
chars[1]='i';
chars[2]='n';
chars[3]='t';
g.drawChars(chars,0,4,xhint+textoffs,yhint+dyhint/2+textoffs);
}

void draw_sign_save(Graphics g)
{
char chars[];

chars=new char[4];
g.drawRect(xsave,ysave,dxsave,dysave);

chars[0]='S';
chars[1]='a';
chars[2]='v';
chars[3]='e';
g.drawChars(chars,0,4,xsave+textoffs,ysave+dysave/2+textoffs);
}

void draw_sign_load(Graphics g)
{
char chars[];

chars=new char[4];
g.drawRect(xload,yload,dxload,dyload);

chars[0]='L';
chars[1]='o';
chars[2]='a';
chars[3]='d';
g.drawChars(chars,0,4,xload+textoffs,yload+dyload/2+textoffs);
}

void draw_sign_skimm(Graphics g)
{
char chars[];

chars=new char[4];
g.drawRect(xskimm,yskimm,dxskimm,dyskimm);

chars[0]='B';
chars[1]='a';
chars[2]='s';
chars[3]='e';
g.drawChars(chars,0,4,xskimm+textoffs,yskimm+dyskimm/2+textoffs);
}

void draw_sign_restart(Graphics g)
{
char chars[];

chars=new char[7];
g.drawRect(xrestart,yrestart,dxrestart,dyrestart);

chars[0]='R';
chars[1]='e';
chars[2]='s';
chars[3]='t';
chars[4]='a';
chars[5]='r';
chars[6]='t';
g.drawChars(chars,0,7,xrestart+textoffs,yrestart+dyrestart/2+textoffs);
}

void draw_sign_csv(Graphics g)
{
char chars[];

chars=new char[3];
g.drawRect(xcsv,ycsv,dxcsv,dycsv);

chars[0]='C';
chars[1]='S';
chars[2]='V';
g.drawChars(chars,0,3,xcsv+textoffs,ycsv+dycsv/2+textoffs);
}
////////////////////////////////////////////////////////////////////////
void repa(int i,int j)
{
int vect[]=new int[2];
int dim=dgrid-6;
int jumdim=dim/2;

getposs(i,j,vect);
repaint(vect[0]-jumdim,vect[1]-jumdim,dim,dim);
}

int[] getposxy(int x,int y)
{int[] ret;
int dx,dy;
double rx,ry;
ret=new int[2];
dx=x-xgrid-dgrid/2;
dy=y-ygrid-dgrid/2;
rx=dx/(double)dgrid;
ry=dy/(double)dgrid;
dx=roundint(rx);
dy=roundint(ry);
if(dx<0)return null;
if(dy<0)return null;
if(dx>8)return null;
if(dy>8)return null;
ret[0]=dy;
ret[1]=dx;
return ret;
}
////////////////////////////////////////////////////////////////////////

boolean is_inrezolva(int x,int y)
{
if(x<xrezolva)return false;
if(y<yrezolva)return false;
if(x>(xrezolva+dxrezolva))return false;
if(y>(yrezolva+dyrezolva))return false;
return true;
}

boolean is_insterge(int x,int y)
{
if(x<xsterge)return false;
if(y<ysterge)return false;
if(x>(xsterge+dxsterge))return false;
if(y>(ysterge+dysterge))return false;
return true;
}

boolean is_ingener(int x,int y)
{
if(x<xgener)return false;
if(y<ygener)return false;
if(x>(xgener+dxgener))return false;
if(y>(ygener+dygener))return false;
return true;
}

boolean is_ingenerhard(int x,int y)
{
if(x<xgenerhard)return false;
if(y<ygenerhard)return false;
if(x>(xgenerhard+dxgenerhard))return false;
if(y>(ygenerhard+dygenerhard))return false;
return true;
}

boolean is_ingenereasy(int x,int y)
{
if(x<xgenereasy)return false;
if(y<ygenereasy)return false;
if(x>(xgenereasy+dxgenereasy))return false;
if(y>(ygenereasy+dygenereasy))return false;
return true;
}

boolean is_inhint(int x,int y)
{
if(x<xhint)return false;
if(y<yhint)return false;
if(x>(xhint+dxhint))return false;
if(y>(yhint+dyhint))return false;
return true;
}

boolean is_inload(int x,int y)
{
if(x<xload)return false;
if(y<yload)return false;
if(x>(xload+dxload))return false;
if(y>(yload+dyload))return false;
return true;
}

boolean is_insalv(int x,int y)
{
if(x<xsave)return false;
if(y<ysave)return false;
if(x>(xsave+dxsave))return false;
if(y>(ysave+dysave))return false;
return true;
}

boolean is_inskimm(int x,int y)
{
if(x<xskimm)return false;
if(y<yskimm)return false;
if(x>(xskimm+dxskimm))return false;
if(y>(yskimm+dyskimm))return false;
return true;
}

boolean is_inrestart(int x,int y)
{
if(x<xrestart)return false;
if(y<yrestart)return false;
if(x>(xrestart+dxrestart))return false;
if(y>(yrestart+dyrestart))return false;
return true;
}

boolean is_incsv(int x,int y)
{
if(x<xcsv)return false;
if(y<ycsv)return false;
if(x>(xcsv+dxcsv))return false;
if(y>(ycsv+dycsv))return false;
return true;
}

boolean is_inclose(int x,int y)
{
if(x<xclose)return false;
if(y<yclose)return false;
if(x>xclose+dclose)return false;
if(y>yclose+dclose)return false;
return true;
}


////////////////////////////////////////////////////////////////////////

void print_vals()
{int i,j;
System.out.println();
for(i=0;i<9;i++)
for(j=0;j<9;j++)
System.out.print(""+vals[i][j]);
System.out.println();
for(i=0;i<9;i++)
{
System.out.print("\n");
for(j=0;j<9;j++)
if(vals[i][j]>0)
System.out.print(""+vals[i][j]);
else
System.out.print(".");
}
System.out.println();
System.out.flush();
}


void get_solution_from_sudoku()
{int i,j;

for(i=0;i<9;i++)
for(j=0;j<9;j++)
vals[i][j]=mysudoku.get_solution_friendly(i+1,j+1);
}

void get_clues_from_sudoku()
{int i,j;
for(i=0;i<9;i++)
for(j=0;j<9;j++)
vals[i][j]=mysudoku.get_clue_friendly(i+1,j+1);
}

void put_clues_into_sudoku()
{int i,j;
mysudoku.clear_clues();
for(i=0;i<9;i++)
for(j=0;j<9;j++)
mysudoku.put_clue_friendly(i+1,j+1,vals[i][j]);
}

////////////////////////////////////////////////////////////////////////

     class randomThread extends Thread {
         public void run() {
    mysudoku.make_random_sudoku();
    get_clues_from_sudoku();
	salv_matr_restart();
	repaint();
}
     }
     class hardrandomThread extends Thread {
         public void run() {
    mysudoku.make_hard_sudoku();
    get_clues_from_sudoku();
	salv_matr_restart();
	repaint();
}
     }

     class easyrandomThread extends Thread {
         public void run() {
    mysudoku.make_easy_sudoku();
    get_clues_from_sudoku();
	salv_matr_restart();
	repaint();
}
     }

     class skimThread extends Thread {
         public void run() {
	put_clues_into_sudoku();
    mysudoku.rem_random_clues();
    get_clues_from_sudoku();
	repaint();
}
     }

     class hintThread extends Thread {
         public void run() {
	put_clues_into_sudoku();
    mysudoku.show_another_clue();
    get_clues_from_sudoku();
	repaint();
}
     }

     class solveThread extends Thread {
         public void run() {
    put_clues_into_sudoku();
    mysudoku.solv();
switch(mysudoku.get_status())
{
case 2:get_solution_from_sudoku();repaint();return;
case 1:System.out.println("Multiple solutions !");return;
case 3:System.out.println("No solution !");return;
default:System.out.println("strange ");return;
}
}
}


}
