// Alexis Yvin - Zacharie-axel amougou-souga
// TD 1 - Aide à la décision - 06/2011

#include <iostream>
#include <sstream>
#include <fstream>
#include <vector>
#include <string>

using namespace std;

// Fonction qui permet d'effectuer la rotation des cases
void rotation_cases(int case_a, int case_b, int case_c, int case_d, int* rubiks)
{
    int* tmp;
    tmp = new int[55];
    tmp[case_a] = rubiks[case_a];
    rubiks[case_a] = rubiks[case_b];
    rubiks[case_b] = rubiks[case_c];
    rubiks[case_c] = rubiks[case_d];
    rubiks[case_d] = tmp[case_a];
    delete[] tmp;
}

// Toutes les permutations possibles
void op_A(int* rubiks)
{
    rotation_cases(3, 19, 46, 30, rubiks);
    rotation_cases(6, 20, 47, 33, rubiks);
    rotation_cases(9, 21, 48, 36, rubiks);
    rotation_cases(39, 45, 43, 37, rubiks);
    rotation_cases(38, 42, 44, 40, rubiks);
}
void op_B(int* rubiks)
{
    rotation_cases(12, 21, 37, 28, rubiks);
    rotation_cases(15, 24, 38, 29, rubiks);
    rotation_cases(18, 27, 39, 30, rubiks);
    rotation_cases(2, 6, 8, 4, rubiks);
    rotation_cases(1, 3, 9, 7, rubiks);
}
void op_C(int* rubiks)
{
    rotation_cases(1, 10, 54, 39, rubiks);
    rotation_cases(2, 11, 51, 42, rubiks);
    rotation_cases(3, 12, 48, 45, rubiks);
    rotation_cases(27, 25, 19, 21, rubiks);
    rotation_cases(24, 26, 22, 20, rubiks);
}
void op_D(int* rubiks)
{
    rotation_cases(1, 25, 52, 28, rubiks);
    rotation_cases(4, 26, 53, 31, rubiks);
    rotation_cases(7, 27, 54, 34, rubiks);
    rotation_cases(12, 10, 16, 18, rubiks);
    rotation_cases(11, 13, 17, 15, rubiks);
}
void op_E(int*  rubiks)
{
    rotation_cases(10, 19, 43, 34, rubiks);
    rotation_cases(13, 22, 44, 35, rubiks);
    rotation_cases(16, 25, 45, 36, rubiks);
    rotation_cases(54, 48, 46, 52, rubiks);
    rotation_cases(51, 47, 49, 53, rubiks);
}
void op_F(int* rubiks)
{
    rotation_cases(7, 16, 46, 37, rubiks);
    rotation_cases(8, 17, 49, 40, rubiks);
    rotation_cases(9, 18, 52, 43, rubiks);
    rotation_cases(28, 34, 36, 30, rubiks);
    rotation_cases(29, 31, 35, 33, rubiks);
}
void op_G(int* rubiks)
{
	op_A(rubiks);
    op_A(rubiks);
	op_A(rubiks);
}
void op_H(int* rubiks)
{
	op_B(rubiks);
	op_B(rubiks);
	op_B(rubiks);
}
void op_I(int* rubiks)
{
	op_C(rubiks);
	op_C(rubiks);
	op_C(rubiks);
}
void op_J(int* rubiks)
{
	op_D(rubiks);
	op_D(rubiks);
	op_D(rubiks);
}
void op_K(int* rubiks)
{
	op_E(rubiks);
	op_E(rubiks);
	op_E(rubiks);
}
void op_L(int* rubiks)
{
	op_F(rubiks);
	op_F(rubiks);
	op_F(rubiks);
}
void op_M(int* rubiks)
{
	op_A(rubiks);
	op_A(rubiks);
}
void op_N(int* rubiks)
{
	op_B(rubiks);
	op_B(rubiks);
}
void op_O(int* rubiks)
{
	op_C(rubiks);
	op_C(rubiks);
}
void op_P(int* rubiks)
{
	op_D(rubiks);
	op_D(rubiks);
}
void op_Q(int* rubiks)
{
	op_E(rubiks);
	op_E(rubiks);
}
void op_R(int* rubiks)
{
	op_F(rubiks);
	op_F(rubiks);
}
void op_S(int* rubiks)
{
	op_G(rubiks);
    op_D(rubiks);
}
void op_T(int* rubiks)
{
	op_H(rubiks);
    op_E(rubiks);
}
void op_U(int* rubiks)
{
	op_I(rubiks);
    op_F(rubiks);
}
void op_V(int* rubiks)
{
    op_A(rubiks);
    op_J(rubiks);
}
void op_W(int* rubiks)
{
    op_B(rubiks);
    op_K(rubiks);
}
void op_X(int* rubiks)
{
    op_C(rubiks);
    op_L(rubiks);
}
void op_Y(int* rubiks)
{
	op_S(rubiks);
	op_S(rubiks);
}
void op_Z(int* rubiks)
{
	op_T(rubiks);
	op_T(rubiks);
}
void op_at(int* rubiks)
{
	op_U(rubiks);
	op_U(rubiks);
}

void lire_fichier(int* rubiks)
{
    //Lecture du fichier
    ifstream fichier("input.txt", ios::in);

    if(fichier) //correct
    {
        char lettre;
        while(fichier.get(lettre))
        {
            switch(lettre)
            {
                case 'A': op_A(rubiks);
                    break;
                case 'B': op_B(rubiks);
                    break;
                case 'C': op_C(rubiks);
                    break;
                case 'D': op_D(rubiks);
                    break;
                case 'E': op_E(rubiks);
                    break;
                case 'F': op_F(rubiks);
                    break;
                case 'G': op_G(rubiks);
                    break;
                case 'H': op_H(rubiks);
                    break;
                case 'I': op_I(rubiks);
                    break;
                case 'J': op_J(rubiks);
                    break;
                case 'K': op_K(rubiks);
                    break;
                case 'L': op_L(rubiks);
                    break;
                case 'M': op_M(rubiks);
                    break;
                case 'N': op_N(rubiks);
                    break;
                case 'O': op_O(rubiks);
                    break;
                case 'P': op_P(rubiks);
                    break;
                case 'Q': op_Q(rubiks);
                    break;
                case 'R': op_R(rubiks);
                    break;
                case 'S': op_S(rubiks);
                    break;
                case 'T': op_T(rubiks);
                    break;
                case 'U': op_U(rubiks);
                    break;
                case 'V': op_V(rubiks);
                    break;
                case 'W': op_W(rubiks);
                    break;
                case 'X': op_X(rubiks);
                    break;
                case 'Y': op_Y(rubiks);
                    break;
                case 'Z': op_Z(rubiks);
                    break;
                case '@': op_at(rubiks);
                    break;
            }
        }
    }
    else
    {
        cout << "Lecture du ficher input.txt impossible." << endl;
    }
    fichier.close();
 }


void affiche(int* rubiks, int mal_placee)
{
    if(mal_placee > 0)
            cout << "Le Rubik's cube melange :" << endl << endl;
    else
        cout << "Le Rubik's cube original :" << endl << endl;

    // Affichage Rubik's cube
    for(int i = 0 ; i < 54 ; i++)
        cout << rubiks[i+1] << " ";

    cout << endl << endl;

    if(mal_placee > 0)
        cout << "Le nombre de cases mal placees est de : " << mal_placee << endl << endl;
    else
        cout << "---------------------------------------------" << endl << endl;
}




int main()
{
    int* rubiks;
    rubiks = new int[55];

    int cpt = 0;
    int mal_placee = 0;

    // Initialisation du Rubik's cube
    for(int i = 0 ; i < 54 ; i++)
    {
        if(i%9 == 0) // Lorsque l'on change de face on incrémente de 1
            cpt++;

        rubiks[i+1] = cpt;
    }

    affiche(rubiks, mal_placee); // Affichage Rubik's cube de base
    lire_fichier(rubiks); // Lecture des opérations à faire

    //On compte le nombre de cases mal placees
    for(int i = 0 ; i < 54 ; i++)
        if(rubiks[i+1] != (i/9)+1)
            mal_placee++;

    affiche(rubiks, mal_placee); // Affichage Rubik's cube mélangé

    delete[] rubiks;

    return 0;
}
