import itertools
import math
import warnings
import time
warnings.filterwarnings("error")
# esta función devuelve todas las permutaciones de obj sin repeticiones
def perms(obj):
perm_set = set()
for item in list(itertools.permutations(obj)):
if item not in perm_set:
perm_set.add(item)
return (perm_set)
# función recursiva para calcular el factorial de un número
def factorial(n):
if (n<10):
return n * factorial(n - 1) if n > 1 else 1
else:
return 0
# Todas las posibilidades de situar paréntesis en la expresión (con 4 dígitos)
formulas = ( (" AQJ x BRK y CSL z DTM ",5),
("E(AQJ x BRK)Ny CSL z DTM ",6),
(" AQJ xE(BRK y CSL)Nz DTM ",6),
(" E(AQJ x BRK y CSL)Nz DTM ",6),
(" E(AQJ x BRK)NyF(CSL z DTM)O",7),
("E(F(AQJ x BRK)Oy CSL)Nz DTM ",7)
)
print ("Comenzamos")
inicio = time.time()
entradas = "2022" # dígitos a utilizar en los cálculos
# las operaciones que vamos a combinar serán la suma, resta, multiplicación, división
# potencia y concatenación. Para cada una se escribe su fórmula en python y su
# expresión matemática de cara a visualizar los resultados
operaciones = (('+','+'), ('-','-'), ('*','x'), ('/','/'), ('**','^'), ('',''))
# preparamos una lista vacía con 100 posiciones para almacenar los resultados
salidas=[]
for i in range(101):
salidas.append([])
indice=0
# recorremos todas las permutaciones de los dígitos de entrada
for digito in perms(entradas):
# recorremos todas las combinaciones posibles de las operaciones disponibles
for operaciones_seleccionadas in list(itertools.combinations_with_replacement(operaciones,len(entradas)-1)):
# con cada combinación de operaciones hacemos todas las permutaciones
for op in perms(operaciones_seleccionadas):
# cada dígito puede tener asignada la operación factorial o no. Se recorren todas las combinaciones
for formula in formulas:
for fact in range (2**formula[1]):
# El cálculo a realizar consiste en la concatenación de dígitos y operaciones
# incluyendo el tratamiento especial de algunos dígitos que en ocasiones pueden llevar
# el cálculo de su factorial.
# Además, la expresión del cálculo incorpora el carácter de paréntesis que corresponda
# según los strings definidos más arriba
# Se preparan dos strings: calculo y expresion
# - calculo: es la sentencia que se evalúa realmente y de la que se obtiene resultado
# - expresion: es la misma sentencia, pero escrita en lenguaje matemático
# (x para multiplicación, ! para factorial y ^ para potencias)
calculo = formula[0]
# Primero sustituimos los dígitos numéricos, caracteres QRST
for orden in range(4):
calculo = calculo.replace(chr(ord('Q')+orden),digito[orden])
expresion = calculo
# Luego metemos las tres operaciones matemáticas seleccionadas, caracteres xyz
for orden in range(3):
calculo = calculo.replace(chr(ord('x')+orden),op[orden][0])
expresion = expresion.replace(chr(ord('x')+orden),op[orden][1])
# Por último ponemos los factoriales donde toque
# caracteres ABCDEF para "factorial("
# y caracteres JKLMNO para cerrar el paréntesis
for orden in range(formula[1]):
calculo = calculo.replace (chr(ord('A')+orden),"factorial(" if (fact & (1<<(orden+1))>0) else "")
calculo = calculo.replace (chr(ord('J')+orden),")" if (fact & (1<<(orden+1))>0) else "")
expresion = expresion.replace (chr(ord('A')+orden),"")
expresion = expresion.replace (chr(ord('J')+orden),"!" if (fact & (1<<(orden+1))>0) else "")
# Una vez montados los strings, limpiamos los espacios que hayan quedado dentro9
calculo = calculo.replace (" ","")
expresion = expresion.replace (" ","")
try:
# Evaluamos el resultado
resultado=eval(calculo)
# El resultado sólo será válido si está entre 1 y 1000, y es un número entero
if (resultado>=0) and (resultado<101) and int(resultado)==resultado:
# cuando el resultado es válido lo guardamos en una lista, en su posición correspondiente
salidas[int(resultado)].append (expresion)
# A veces las expresiones no se pueden evaluar porque aparecen divisiones por cero, paréntesis
# concatenados con dígitos y otras incorrecciones. Las descartamos.
except (ZeroDivisionError):
pass
except (TypeError, SyntaxError):
pass
indice = indice + 1
fin = time.time()
soluciones= 0
for i in range (101):
if len(salidas[i])>0:
print (i, " -> ", end="")
for j in range (min(10, len(salidas[i]))):
print (salidas[i][j], end="")
if (j<min(10, len(salidas[i]))-1):
print (", ",end="")
print ("")
soluciones = soluciones + 1
print ("Se han encontrado", soluciones, "soluciones en {:,.2f}".format(fin-inicio), "segundos")