#include "Q1.h"

vector <unsigned> poss_case(vector <unsigned> tab_ligne, vector <unsigned> tab_collonne, vector< vector <unsigned> > tab_case)
{
    vector <unsigned> possibilites;
    for(unsigned i=0 ; i<tab_ligne.size() ; i++) possibilites.push_back(i+1);

    for(unsigned i=0 ; i<tab_ligne.size() ; i++)
    {
        if(position_in_vector(possibilites, tab_ligne[i]) != possibilites.size()+1) /* on cherche si la contrainte impose qqchose */
        {
            possibilites.erase(possibilites.begin() + position_in_vector(possibilites, tab_ligne[i])); // on enlève la possibilité
        }

        if(position_in_vector(possibilites, tab_collonne[i]) != possibilites.size()+1) /* on cherche si la contrainte impose qqchose */
        {
            possibilites.erase(possibilites.begin() + position_in_vector(possibilites, tab_collonne[i])); // on enlève la possibilité
        }
    }
    for(unsigned i=0 ; i<tab_case.size() ; i++)
    {
        for(unsigned j=0 ; j<tab_case[i].size() ; j++)
        {
            if(position_in_vector(possibilites, tab_case[i][j]) != possibilites.size()+1) /* on cherche si la contrainte impose qqchose */
            {
                possibilites.erase(possibilites.begin() + position_in_vector(possibilites, tab_case[i][j])); // on enlève la possibilité
            }
        }
    }
    return possibilites;
}

unsigned position_in_vector(vector <unsigned> possibilites, unsigned value)
{
    for(unsigned i=0 ; i<possibilites.size() ; i++)
    {
        if(value == possibilites[i]) return i;
    }
    return possibilites.size()+1;
}

vector< vector <unsigned> > Super_resolution_propagation_contraintes(vector< vector <unsigned> > sudoku, unsigned mode) // ajouter en argument une fonction de contraintes ?
{
    vector < vector<unsigned> > cases_et_poss;
    //cout << " ------------ ---------------" << endl;
    //affichage_sudoku(sudoku);
    for(unsigned i=0 ; i<sudoku.size(); i++)
    {
        for(unsigned j=0 ; j< sudoku[i].size() ; j++) // Parcour de toutes les cases pour en choisir les valeurs.
        {
            if(sudoku[i][j] == 0)
            {
                vector <unsigned> tab_ligne = sudoku[i]; // la ligne correspondante
                vector <unsigned> tab_collonne = get_collone(sudoku, j); // la collonne correspondante
                vector < vector <unsigned> > tab_case = get_case(sudoku, i/mode, j/mode, mode); // la case correspondante
                vector <unsigned> possibilites = poss_case(tab_ligne, tab_collonne, tab_case); // possibilitès
                for(unsigned k=0; k<possibilites.size() ; k++) // récursivité
                {
                    vector< vector <unsigned> > sudoku_to_send = sudoku;
                    sudoku_to_send[i][j] = possibilites[k];
                    sudoku_to_send = Super_resolution_propagation_contraintes(sudoku_to_send, mode);
                    if(est_total_sudoku(sudoku_to_send)) return sudoku_to_send;
                }
            }
        }
    }
    return sudoku;
}

vector< vector <unsigned> > Super_resolution_propagation_contraintes2(vector< vector <unsigned> > sudoku, unsigned mode) // ajouter en argument une fonction de contraintes ?
{
    if(est_total_sudoku(sudoku)) return sudoku;
    vector < vector<unsigned> > cases_et_poss;
    vector < vector <unsigned> > tab_possibilites;
    vector <unsigned> tab_possibilites_j;
    vector <unsigned> tab_possibilites_x;
    //cout << " ------------ ---------------" << endl;
    //affichage_sudoku(sudoku);
    for(unsigned i=0 ; i<sudoku.size(); i++)
    {
        for(unsigned j=0 ; j< sudoku[i].size() ; j++) // Parcour de toutes les cases pour en choisir les valeurs.
        {
            if(sudoku[i][j] == 0)
            {
                vector <unsigned> tab_ligne = sudoku[i]; // la ligne correspondante
                vector <unsigned> tab_collonne = get_collone(sudoku, j); // la collonne correspondante
                vector < vector <unsigned> > tab_case = get_case(sudoku, i/mode, j/mode, mode); // la case correspondante
                tab_possibilites.push_back(poss_case(tab_ligne, tab_collonne, tab_case)); // possibilitès
                tab_possibilites_j.push_back(j);
                tab_possibilites_x.push_back(i);
            }
        }
    }

    unsigned min=mode*mode, position;
    for(unsigned i=0 ; i<tab_possibilites.size() ; i++)
    {
        if(tab_possibilites[i].size() == 0) return sudoku; // inutile
        if(tab_possibilites[i].size()<min)
        {
            min = tab_possibilites[i].size();
            position = i;
        }
    }
    /*cout << "there" << endl;
    affichage_sudoku(sudoku);
    system("pause");*/

    for(unsigned k=0; k<tab_possibilites[position].size() ; k++) // récursivité
    {
        vector< vector <unsigned> > sudoku_to_send = sudoku;
        sudoku_to_send[tab_possibilites_x[position]][tab_possibilites_j[position]] = tab_possibilites[position][k];
        sudoku_to_send = Super_resolution_propagation_contraintes2(sudoku_to_send, mode);
        if(est_total_sudoku(sudoku_to_send)) return sudoku_to_send;
    }
    return sudoku;
}

vector <unsigned> get_collone(vector< vector <unsigned> > tableau, unsigned numero_collonne)
{
    vector <unsigned> temp;
    for(unsigned i=0 ; i<tableau.size() ; i++)
    {
        temp.push_back(tableau[i][numero_collonne]);
    }
    return temp;
}

vector < vector <unsigned> > get_case(vector< vector <unsigned> > tableau, unsigned numero_ligne, unsigned numero_collonne, unsigned mode)
{
    vector < vector < unsigned> > temp;
    vector <unsigned> temp_ligne;
    for(unsigned i=mode*numero_ligne ; i< mode*(numero_ligne+1) ; i++)
    {
        temp_ligne.clear();
        for(unsigned j=mode*numero_collonne ; j< mode*(numero_collonne+1) ; j++)
        {

            temp_ligne.push_back(tableau[i][j]);
        }
        temp.push_back(temp_ligne);
    }
    return temp;
}

bool est_total_sudoku (vector< vector <unsigned> > sudoku)
{
    for(unsigned i=0 ; i<sudoku.size() ; i++)
    {
        for(unsigned j=0 ; j<sudoku[i].size() ; j++)
        {
            if(sudoku[i][j] == 0) return false;
        }
    }
    return true;
}

void affichage_sudoku(vector< vector <unsigned> > sudoku)
{
    for(unsigned i=0 ; i<sudoku.size() ; i++)
    {
        for(unsigned j=0 ; j<sudoku[i].size() ; j++)
        {
            cout << sudoku[i][j] << " ";
        }
        cout << endl;
    }
}

vector < vector <unsigned> > creation_sudoku_vide(unsigned mode)
{
    vector < vector <unsigned> > tobereturn;
    vector <unsigned> temp;
    temp.resize(mode*mode,0);
    for(unsigned i=0 ; i<mode*mode ; i++)
    {
        tobereturn.push_back(temp);
    }
    return tobereturn;
}
