# file cryptarithme.py # brief solution générique des cryptarithme # author Johan Lachenal # date 17 Octobre 2022 # ce fichier contient l'algorithme générique résolvant les cryptarithmes, plus tard il contiendra un générateur aléatoire de cryptarithme # Pour que le résolveur d'énigmes de cryptarithme fonctionne, il est nécessaire d'effectuer la commande : # pip install cpmpy import numpy as np import re import itertools from cpmpy import * # brief résout un cryptarithme donné et affiche le résultat # param ListeMots liste des mots du cryptarithme entré # param ListeOperateurs liste des opérateurs du cryptarithme entré # param ListeLettres liste des lettres associés à des variables du cryptarithme # param ListePosition liste temporaire servant à prendre les positions des variables dans la liste ListeLettres pour un mot que l'on remet ensuite a null # param ListePostion liste de liste de positions des variables dans la liste ListeLettres # param exposant10 liste temporaire servant à prendre les exposants pour chacune des lettres d'un mot # param exposants10 liste de liste d'exposant pour chque mot # param ConstraintAssemblingList liste des operations entre les variables d'un mot # param equalposition postion du egal dans la liste des opérateurs # param BigFirstEquationConstraintPart partie de contrainte avant le egal # param BigSecondEquationConstraintPart partie de contrainte après le egal # param model, model auquel on ajoute les contraintes def cryptarithmeGenerique (s): ListeMots=[] ListeOperateurs=[] ListeLettres=[] ListePosition=[] ListePositions=[] exposant10=[] exposants10=[] ConstraintAssemblingList=[] BigFirstEquationConstraintPart=[] equalposition=0 # attrape la liste de lettres lettres = "".join(set(re.findall("[A-Z]", s))) # attrape la liste de mots mots = s.split() if(mots[0]=='-'): print("pas de - comme opérateur devant la chaîne de caractère") return for i in range(0,len(mots),2): ListeMots.append(mots[i]) # print(ListeMots) # attrape la liste d'opérateurs for i in range(1,len(mots),2): ListeOperateurs.append(mots[i]) # print(ListeOperateurs) # associe à une lettre ses possibilités for i in range(0,len(lettres)): if(lettres[i] in [ListeMots[y][0] for y in range(0,len(ListeMots))]): ListeLettres.append([lettres[i],intvar(1,9, shape=1)]) else: ListeLettres.append([lettres[i],intvar(0,9, shape=1)]) #print(ListeLettres) # associe pour chaque mot une liste des positions des variables contenu dans ListeLettres for i in ListeMots: # print(i) for y in i: # print(y) for w in range(0,len(ListeLettres)): # print(w) # print(ListeLettres[w][0]) if(y==ListeLettres[w][0]): ListePosition.append(w) break ListePositions.append(ListePosition) ListePosition=[] # print(ListePositions) # associe pour chaque mot une liste d'exposant for y in ListeMots: for i in range(0,len(y)): exposant10.append(10**i) exposants10.append(exposant10) exposant10=[] # print(exposants10) # creation des parties de la contrainte globale du cryptarithme for i in range(0,len(ListeMots)): ConstraintAssemblingList.append(sum([ListeLettres[ListePositions[i][y]][1]*10**(len(ListeMots[i])-y-1) for y in range(0,len(ListeMots[i]))])) # print(ConstraintAssemblingList) # assemblage des parties de la contrainte globale du cryptarithme avant le = BigFirstEquationConstraintPart=ConstraintAssemblingList[0] for i in range(0,len(ListeOperateurs)): if(ListeOperateurs[i]=='+'): BigFirstEquationConstraintPart = BigFirstEquationConstraintPart + ConstraintAssemblingList[i+1] if(ListeOperateurs[i]=='-'): BigFirstEquationConstraintPart = BigFirstEquationConstraintPart - ConstraintAssemblingList[i+1] if(ListeOperateurs[i]=='*'): BigFirstEquationConstraintPart = BigFirstEquationConstraintPart * ConstraintAssemblingList[i+1] if(ListeOperateurs[i]=='/'): BigFirstEquationConstraintPart = BigFirstEquationConstraintPart / ConstraintAssemblingList[i+1] print(BigFirstEquationConstraintPart) if(ListeOperateurs[i]=='='): equalposition=i break # print(BigFirstEquationConstraintPart) # assemblage des parties de la contrainte globale du cryptarithme après le = BigSecondEquationConstraintPart=ConstraintAssemblingList[equalposition+1] for i in range(equalposition,len(ListeOperateurs)): if(ListeOperateurs[i]=='+'): BigSecondEquationConstraintPart = BigSecondEquationConstraintPart + ConstraintAssemblingList[i+1] if(ListeOperateurs[i]=='-'): BigSecondEquationConstraintPart = BigSecondEquationConstraintPart + -ConstraintAssemblingList[i+1] if(ListeOperateurs[i]=='*'): BigSecondEquationConstraintPart = BigSecondEquationConstraintPart * ConstraintAssemblingList[i+1] if(ListeOperateurs[i]=='/'): BigSecondEquationConstraintPart = BigSecondEquationConstraintPart / ConstraintAssemblingList[i+1] print(BigSecondEquationConstraintPart) # print(BigSecondEquationConstraintPart) # Création du model et de ses contraintes model = Model() # Mise en place de la contrainte globale model += (BigFirstEquationConstraintPart == BigSecondEquationConstraintPart) # Mise en place de la contrainte où toutes les lettres sont différentes model += AllDifferent(ListeLettres[i][1] for i in range(0,len(ListeLettres))) # Mise en place de la contrainte disant que les premières lettres des mots sont différentes de 0 for i in range(0,len(ListeMots)): model += (ListeLettres[ListePositions[i][0]][1]) > 0 if model.solve(): print(s) for i in range(0,len(ListeMots)): print(ListeMots[i]," =",[x.value() for x in [ListeLettres[ListePositions[i][y]][1] for y in range(0,len(ListeMots[i]))]]) else: print("No solution found") cryptarithmeGenerique("SEND + MORE = MONEY") cryptarithmeGenerique("HUIT + HUIT = SEIZE") cryptarithmeGenerique("UN + UN + NEUF = ONZE") cryptarithmeGenerique("UN + TROIS - NEUF = ONZE") cryptarithmeGenerique("UN * UN = ONZE") cryptarithmeGenerique("UNN / UN = UN")