/* L représente une addition. C'est une liste de listes. La première sous-liste représente le résultat de l'addition, les autres les nombres additionnés. Par exemple : ?- crypt([[S,E,I,Z,E],[H,U,I,T],[H,U,I,T]]). S = 1, E = 6, I = 5, Z = 0, H = 8, U = 2, T = 3 ; S = 1, E = 8, I = 5, Z = 0, H = 9, U = 2, T = 4 ; false. ?- crypt([[O,N,Z,E],[U,N],[U,N],[N,E,U,F]]). O = 2, N = 1, Z = 4, E = 9, U = 8, F = 7 ; false. */ crypt(L) :- affectation_toutes(L,[0,1,2,3,4,5,6,7,8,9]),teste_premiers_chiffres(L), teste_addition(L). /* affecter une valeur à une variable à partir d'un domaine, et enlever la valeur du domaine : choix(Variable, Domaine, DomaineRéduit) */ choix(X, [X|R], R). choix(X, [Y|Xs], [Y|Ys]):- choix(X, Xs, Ys). /* affecter des valeurs à des variables à partir d'un domaine, en réduire le domaine au fur et à mesure : affectation(ListeVariables,Domaine, DomaineRéduit) */ affectation([], R,R). affectation([V|Vs], Dom,R):- var(V),!, /* on affecte une valeur si la variable n'est pas déjà instanciée */ choix(V, Dom, NewDom), affectation(Vs, NewDom,R). affectation([_|Vs], Dom,R) :- affectation(Vs,Dom,R). /* si la variable a déjà été instanciée, on passer à la suivante */ /* affecter des valeurs à des variables qui sont dans une liste de listes (chaque liste représente un des nombres de l'addition). Si on affecte une valeur à une variable de l'une des listes, par unification elle prend aussi une valeur dans les autres listes où elle est présente. C'est pourquoi dans affectation il est possible que certaines variables soient déjà instanciées */ affectation_toutes([],_). affectation_toutes([L|LL],D) :- affectation(L,D,ND), affectation_toutes(LL,ND). /* on vérifie que le chiffre le plus significatif de chaque nombre est non nul (c'est à dire le premier élément de chaque liste) */ teste_premiers_chiffres([]). teste_premiers_chiffres([[X|_]|L]) :- X\==0, teste_premiers_chiffres(L). /* pour vérifier la contraite d'addition, on calcule le nombre correspondant à la première sous-liste, qui conrrespond au résultat, on calcule la somme des autres listes, et les 2 résultats doivent être identiques */ teste_addition([X|L]) :- calcule(X,S),calcule_lignes(L,S). /* pour calculer le nombre représenté par une liste, on commence par la retourner puis on calcule */ calcule(L,R) :- reverse(L,L1), calc(L1,R). calc([],0). calc([X|L],R) :- calc(L,RR), R is X+10*RR. /* pour chaque nombre sommé, on calcule le nombre représenté par la liste et on ajoute le tout */ calcule_lignes([],0). calcule_lignes([X|L],R) :- calcule_lignes(L,RR), calcule(X,S), R is RR+S.