package fanch.multijeu.sudoku.data;

import java.util.ArrayList;

import fanch.multijeu.common.utils.IntUtils;

public class SudokuGenerator extends Sudoku {

    private Sudoku mResolved = new Sudoku();

    public SudokuGenerator()
    {
        super();
    }

    public Sudoku getResolved()
    {
        return mResolved;
    }


    public void generate(int n)
    {
        int k = 81-n;
        OldSudoku sos = OldSudoku.generateFilled();
        mResolved=new Sudoku(sos.toString());
        loadFromString(sos.toString());
        while(clearRandom(k)<k);
    }

    protected boolean clearRandom2() {
        int histo[] = new int[9];
        final int MIN=1;
        ArrayList<Integer> l = new ArrayList<>();
        for(int i=0; i<81; i++)
        {
            final int x = get(i);
            if(x>=1 && x<=9)
                histo[x-1]++;
        }

        for(int i=0; i<81; i++)
        {
            final int x = get(i);
            if(x>0 && histo[x-1]>MIN) l.add(i);
        }

        int x = IntUtils.rand(0, l.size()-1);
        set(l.get(x),0);
        return true;
    }

    protected boolean clearRandom() {
        int histo[] = new int[9];
        int total =0;
        final int MIN=2;
        final int FACTOR=3;

        for(int i=0; i<81; i++)
        {
            final int x = get(i);
            if(x>=1 && x<=9)
                histo[x-1]++;
        }

        for(int i=0; i<9; i++) {
            if(histo[i]>MIN) total += histo[i]*FACTOR;
        }


        int n = IntUtils.rand(0, total-1);
        int val=0;
        for(int i=0; i<9; i++)
        {
            n-=histo[i]*FACTOR;
            if(n<0)
            {
                val=i+1;
                break;
            }
        }
        if(val==0)
            return false;

        int max=0;
        int imax=-1;
        for(int i=0; i<81; i++)
        {
            if(get(i)==val)
            {
                final int x = count(i);
                if(x>max)
                {
                    max=x;
                    imax=i;
                }
            }
        }
        if(imax==-1)
            return false;
        mPuzzle[imax]=0;

        return true;
    }

    protected int clearRandom(int n)
    {
        int K=81*2;
        String last=toString();
        for(int i=0; i<n; i++)
        {
            int k;
            for( k=0; k<K; k++)
            {
                boolean b = clearRandom2();
                Sudoku test = copy();
                try{
                    if(!test.resolve()) throw new Exception();
                    last=toString();
                    break;
                }catch (Exception e)
                {
                    loadFromString(last);
                }
            }
            if(k==K) return i;
            //throw new RuntimeException("Erreur nombre d'echec trop important i="+i+"  "+toString());
        }
        return n;
    }

    protected int countLine(int y)
    {
        int n = 0;
        for(int i=0; i<9; i++)
            if(get(i, y)!=0)
                n++;
        return n;
    }

    protected int countColumn(int x)
    {
        int n = 0;
        for(int i=0; i<9; i++)
            if(get(x, i)!=0)
                n++;
        return n;
    }

    protected int countSquare(int x, int y)
    {
        int n = 0;
        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(get(i,j)!=0) n++;
        return n;
    }


    protected int count(int x, int y)
    {
        return countSquare(x,y)+countColumn(x)+countLine(y);
    }

    protected int count(int i)
    {
        return count(i%9, i/9);
    }

}
