package fanch.multijeu.sudoku.data;

public class Sudoku {
    public static int LINE_COUNT=9;
    public static int COLUMN_COUNT=9;
    public static int CELL_COUNT=LINE_COUNT*COLUMN_COUNT;

    protected static final int[][] INDEXES = {
            {0,1,2,9,10,11,18,19,20}, {3,4,5,12,13,14,21,22,23}, {6,7,8,15,16,17,24,25,26},
            {27,28,29,36,37,38,45,46,47}, {30,31,32,39,40,41,48,49,50}, {33,34,35,42,43,44,51,52,53},
            {54,55,56,63,64,65,72,73,74}, {57,58,59,66,67,68,75,76,77}, {60,61,62,69,70,71,78,79,80}
    };

    protected int[] mPuzzle = new int[81];

    protected Sudoku(){}

    public Sudoku(String str)
    {
        loadFromString(str);
    }

    public Sudoku copy()
    {
        Sudoku s = new Sudoku();
        for(int i=0; i<CELL_COUNT; i++)
            s.set(i, get(i));
        return s;
    }

    public boolean resolve()
    {
        SimpleSudokuResolver sr = new SimpleSudokuResolver(this);
        sr.resolve();
        return isFinish();
    }

    public String toString()
    {
        String s="";
        for(int i=0; i<CELL_COUNT; i++)
            s+=""+get(i%LINE_COUNT, i/LINE_COUNT);
        return s;
    }

    public void loadFromString(String str)
    {
        for(int i=0; i<CELL_COUNT; i++)
        {
            byte b = (byte) (str.charAt(i) - '0');
            if(b<0 || b>LINE_COUNT) b=0;
            set(i%LINE_COUNT,i/LINE_COUNT,b);
        }
    }


    public void clear()
    {
        int i;
        for(i=0; i<CELL_COUNT; i++) mPuzzle[i]=0;
    }

    public void set(int i, int j, int c)
    {
        mPuzzle[j*LINE_COUNT+i]=c;
    }

    public void set(int i, int c)
    {
        mPuzzle[i]=c;
    }

    public int get(int i)
    {
        return mPuzzle[i];
    }

    public int get(int i, int j)
    {
        return mPuzzle[j*LINE_COUNT+i];
    }


    protected boolean checkColumn( int x, int y, int c)
    {
        int i;
        for(i=0; i<9; i++)
            if(y!=i && get(x, i)==c) return false;
        return true;
    }

    protected boolean checkColumn( int x, int y)
    {
        return checkColumn(x, y, get(x,y));
    }

    private boolean checkLine( int x, int y,  int c)
    {
        int i;
        for(i=0; i<9; i++)
            if(x!=i && get(i, y)==c) return false;
        return true;
    }

    protected boolean checkLine( int x, int y)
    {
        return checkLine(x, y, get(x,y));
    }

    /*private boolean checkSquare(int x,  int y,  int c)
    {
        int dx,  dy;
        int i, j;
        if(x>=6) dx=6; else if(x>=3) dx=3; else dx=0;
        if(y>=6) dy=6; else if(y>=3) dy=3; else dy=0;
        for(i=dx; i<dx+3; i++)
            for(j=dy; j<dy+3; j++)
                if(x!=i && j!=y && get( i, j)==c) return false;
        return true;
    }*/
    private boolean checkSquare(int x,  int y,  int c)
    {
        int square[] = INDEXES[(y/3)*3+x/3];
        int offset = y*9+x;
        for(int i=0; i<square.length; i++)
                if(offset!=square[i] && get(square[i])==c)
                    return false;
        return true;
    }

    protected boolean checkSquare( int x, int y)
    {
        return checkSquare(x, y, get(x,y));
    }

    public boolean checkCell(int x, int y, int c)
    {
        return checkLine(x,y,c) && checkColumn(x, y,c) && checkSquare(x, y, c);
    }

    public boolean check(){
        for(int i=0; i<CELL_COUNT; i++)
        {
            final int x = i%LINE_COUNT;
            final int y = i/LINE_COUNT;
            final int val = get(i);

            if(!checkCell(x,y,val))
                return false;
        }
        return true;
    }

    public boolean isFinish(){
        for(int i=0; i<CELL_COUNT; i++)
        {
            final int x = i%LINE_COUNT;
            final int y = i/LINE_COUNT;
            final int val = get(i);
            if(val==0 || !checkCell(x,y,val))
                return false;
        }
        return true;
    }

}
