import org.chocosolver.solver.Model;
import org.chocosolver.solver.Solver;
import org.chocosolver.solver.variables.IntVar;
import org.chocosolver.solver.constraints.extension.Tuples;

public class Exercice1 {
    public static final int HEURISTIQUE_DEFAUT = 0;
    public static final int HEURISTIQUE_DOMOVERWDEG = 1;
    public static final int HEURISTIQUE_IMPACT_BASED_SEARCH = 2;
    public static final int HEURISTIQUE_ACTIVITY = 3;
    public static final String COHERENCE_BORNES = "BC";
    public static final String COHERENCE_DOMAINES = "AC";

    public static final int RESTART_AUCUN = 0;
    public static final int RESTART_LUBY = 1;
    public static final int RESTART_GEOMETRIQUE = 2;

    public static void main(String[] args) {
    	
    	
    	final int N = 4;
    	final int F = 4;
        final String coherence = COHERENCE_BORNES;

        Model model = new Model("Quatre cubes");
        
        // Énumération des combinaisons dans un tableau. 1: rouge, 2:vert, 3:bleu, 4:jaune
        int[][] tableauCubeUn = new int[][]{
            {3,4,1,2},{3,2,1,1},{3,2,1,4},{3,1,1,2},
            {2,3,4,1},{2,2,4,1},{2,1,4,3},{2,1,4,2},
            {1,2,3,4},{1,2,3,1},{1,4,3,2},{1,1,3,2},
            {4,2,2,1},{4,3,2,1},{4,1,2,2},{4,1,2,3},
            {2,4,1,2},{2,1,1,3},{2,2,1,4},{2,3,1,1},
            {1,4,2,2},{1,3,2,1},{1,2,2,4},{1,1,2,3},
            };
            
        int[][] tableauCubeDeux = new int[][]{
            {4,2,3,2},{4,1,3,3},{4,2,3,2},{4,3,3,1},
            {2,1,2,3},{2,3,2,1},{2,3,2,4},{2,4,2,3},
            {3,1,4,3},{3,3,4,1},{3,2,4,2},{3,2,4,2},
            {2,1,2,3},{2,3,2,1},{2,4,2,3},{2,3,2,4},
            {1,3,3,4},{1,4,3,3},{1,2,3,2},{1,2,3,2},
            {3,4,1,3},{3,3,1,4},{3,2,1,2},{3,2,1,2},
            }; 
        int[][] tableauCubeTrois = new int[][]{
            {3,4,1,4},{3,4,1,4},{3,2,1,4},{3,4,1,2},
            {4,4,2,4},{4,4,2,4},{4,1,2,3},{4,3,2,1},
            {1,4,3,4},{1,4,3,4},{1,4,3,2},{1,2,3,4},
            {2,4,4,4},{2,4,4,4},{2,1,4,3},{2,3,4,1},
            {4,4,4,2},{4,2,4,4},{4,3,4,1},{4,1,4,3},
            {4,4,4,2},{4,2,4,4},{4,3,4,1},{4,1,4,3},
            }; 
        int[][] tableauCubeQuatre = new int[][]{
            {3,1,4,2},{3,2,4,1},{3,1,4,4},{3,4,4,1},
            {1,1,4,2},{1,2,4,1},{1,4,4,3},{1,3,4,4},
            {4,1,3,2},{4,2,3,1},{4,1,3,4},{4,4,3,1},
            {4,1,1,2},{4,2,1,1},{4,3,1,4},{4,4,1,3},
            {2,3,1,4},{2,4,1,3},{2,1,1,4},{2,4,1,1},
            {1,4,2,3},{1,3,2,4},{1,1,2,4},{1,4,2,1},
            }; 
        
        // Création des tuples à partir des tableaux pour implémenter les contraintes table.
        Tuples tuplesCubeUn = new Tuples(tableauCubeUn, true);
        Tuples tuplesCubeDeux = new Tuples(tableauCubeDeux, true);
        Tuples tuplesCubeTrois = new Tuples(tableauCubeTrois, true);
        Tuples tuplesCubeQuatre = new Tuples(tableauCubeQuatre, true);
        
        IntVar[][] facesCubes = model.intVarMatrix("x", N, F, 1, 4, false);
        
    	model.table(facesCubes[0], tuplesCubeUn).post();
    	model.table(facesCubes[1], tuplesCubeDeux).post();
    	model.table(facesCubes[2], tuplesCubeTrois).post();
    	model.table(facesCubes[3], tuplesCubeQuatre).post();
        
    	// On créé la transpose de la matrice facesCubes pour pouvoir effectuer la contrainte ALLDIFFERENT.
        IntVar[][] faceRectangulaires = new IntVar[F][N];
        for (int noFace = 0; noFace < F; noFace++) {
        	for (int noCube = 0; noCube < N; noCube++) {
	    		faceRectangulaires[noFace][noCube] = facesCubes[noCube][noFace];
        	}
    		model.allDifferent(faceRectangulaires[noFace], coherence).post();
        }
        
        // Creation et lancement du solveur. 
        Solver solver = model.getSolver();
        solver.findSolution();
        
     // On affiche la solution.
        System.out.print("          ");
        for (int noCube = 0; noCube < N; noCube++) {
        	System.out.print(" Cube ");
        	System.out.print(noCube);
        	System.out.print("    ");
        }
        System.out.println("");
        for (int noFace = 0; noFace < F; noFace++) {
        	System.out.print(" Face ");
        	System.out.print(noFace);
        	System.out.print("   ");
        	for (int noCube = 0; noCube < N; noCube++) {
                if (faceRectangulaires[noFace][noCube].getValue() == 1) {
                    System.out.print("    R    ");
                }else if (faceRectangulaires[noFace][noCube].getValue() == 2) {
                	System.out.print("    V    ");
                }else if (faceRectangulaires[noFace][noCube].getValue() == 3) {
                	System.out.print("    B    ");
                }else {
                	System.out.print("    J    ");
                }
                
                System.out.print("  ");
            }
            System.out.println("");
        }
        solver.printStatistics();
    }
}

