◂ 21 décembre 2022 ▸
Monkey Math : Calculer une expression mathématique, puis en résoudre une autre
vbjj: fcml * mwwn
mbmw: 2
gstw: cldd / rvtn
brsc: 5
bpjn: 11
⋮
- moncode.py
- codeReductionEquation.py
- calcul.py
from functools import cache
f = open("input.txt", 'r')
lines = [line[:-1] for line in f.readlines()]
SILLY_MONKEY = 'root'
MONKEY_ME = 'humn'
monkeys = {}
for line in lines:
tk = line.split()
monkeyName = tk[0][:-1]
# On stocke soit la valeur, soit les trois parties de l'opération. Pas terrible de mélanger les types, mais voilà:
if len(tk) == 2:
monkeys[monkeyName] = int(tk[1])
else:
monkeys[monkeyName] = tk[1:]
def getResult(monkeyName):
global monkeys
calcul = monkeys[monkeyName]
if type(calcul) == int:
return calcul
else:
mk1, operation, mk2 = calcul
valMk1 = getResult(mk1)
valMk2 = getResult(mk2)
if operation == '+':
return valMk1 + valMk2
elif operation == '-':
return valMk1 - valMk2
elif operation == '/':
return valMk1 // valMk2 # changé valMk1 / valMk2 après avoir vérifié à la main que les divisions étaient bien toutes entières
elif operation == '*':
return valMk1 * valMk2
else:
print("Argh, opération inconnue", calcul)
exit(1)
print("Réponse partie 1:", getResult('root'))
### PARTIE 2 avec trois façons différentes ! ###
monkeys[SILLY_MONKEY][1] = '-' # égalité si ça retourne 0 !
# Utilisée par les méthodes 1 et 3
@cache # on gagne jusqu'à un facteur 10, mais rien de problématique sans
def isNombre(monkeyName):
t = monkeys[monkeyName]
if type(t) == list:
if MONKEY_ME in t: # utilise ma valeur inconnue
return False
return isNombre(t[0]) and isNombre(t[2])
else:
return True
### Partie 2, (1) méthode résolution maison; facile car l'inconnue n'apparaît qu'une fois ###
print("\n====== Partie 2, méthode de résolution maison =======")
def mySolve(monkeyName, valeurVoulue):
if monkeyName == MONKEY_ME:
return valeurVoulue
if isNombre(monkeyName):
return getResult(monkeyName)
mk1, operation, mk2 = monkeys[monkeyName]
isMk1Nombre = isNombre(mk1)
if operation == '+':
if isMk1Nombre:
return mySolve(mk2, valeurVoulue - getResult(mk1))
else:
return mySolve(mk1, valeurVoulue - getResult(mk2))
elif operation == '-':
if isMk1Nombre:
return mySolve(mk2, getResult(mk1) - valeurVoulue)
else:
return mySolve(mk1, valeurVoulue + getResult(mk2))
elif operation == '/':
if isMk1Nombre:
return mySolve(mk2, getResult(mk1) // valeurVoulue)
else:
return mySolve(mk1, valeurVoulue * getResult(mk2))
elif operation == '*':
if isMk1Nombre:
return mySolve(mk2, valeurVoulue // getResult(mk1))
else:
return mySolve(mk1, valeurVoulue // getResult(mk2))
print("Réponse partie 2 (méthode de résolution maison):", mySolve(SILLY_MONKEY, 0))
### Partie 2, (2) méthode par dichotomie pour trouver le zéro de getResult('root'). ###
### fonctionne même si l'inconnue apparaît plus d'une fois et même si l'équation est difficile à résoudre.
### En revanche, il faut être sûr qu'il n'y ait pas des zéros non entiers à rejeter, ni que le zéro soit un max ou un min
print("\n====== Partie 2, méthode de résolution par dichotomie =======")
def sign(x):
return x > 0 and 1 or x<0 and -1 or 0
def signeDifferenceSelonValeur(maValeur):
global monkeys
monkeys[MONKEY_ME] = maValeur
if 'cache' in str(getResult): # on change les valeurs, donc il faut vider le cache s'il y en a un
getResult.cache_clear()
return sign(getResult(SILLY_MONKEY))
borneInferieure = -10**20
borneSuperieure = 10**20 # Ça devrait être plus grand que la valeur à trouver…
# ajuster les bornes si 10**20 ne suffit pas à obtenir un changement de signe
sgnBorneInf = signeDifferenceSelonValeur(borneInferieure)
sgnBorneSup = signeDifferenceSelonValeur(borneSuperieure)
while sgnBorneInf == sgnBorneSup:
borneInferieure *= 10
borneSuperieure *= 10
print("Méthode par dichotomie: trouvé des signes différents ! On peut commencer.")
# démarrer la dichotomie
while borneInferieure < borneSuperieure-1:
milieuBornes = (borneInferieure+borneSuperieure)//2
sgnMilieu = signeDifferenceSelonValeur(milieuBornes)
if (sgnMilieu == sgnBorneInf):
(borneInferieure,borneSuperieure) = (milieuBornes, borneSuperieure)
else:
(borneInferieure,borneSuperieure) = (borneInferieure, milieuBornes)
# afficher le résultat
if signeDifferenceSelonValeur(borneInferieure) == 0:
print("Réponse partie 2 (méthode par dichotomie):", borneInferieure)
elif signeDifferenceSelonValeur(borneSuperieure) == 0:
print("Réponse partie 2 (méthode par dichotomie):", borneSuperieure)
else:
print("Réponse partie 2 (méthode par dichotomie): pas trouvé de valeur entière…")
### Partie 2, (3) méthode de résolution par sympy, ou par un site ou un logiciel ###
import sympy
print("\n====== Partie 2, méthode de résolution par sympy, ou par un site ou un logiciel =======")
def toMathString(monkeyName):
global monkeys
if monkeyName == 'humn':
return 'x'
if isNombre(monkeyName):
return(str(getResult(monkeyName)))
mk1, operation, mk2 = monkeys[monkeyName]
return '(' + toMathString(mk1) + operation + toMathString(mk2) + ')'
equation = toMathString(SILLY_MONKEY)
sols=sympy.solve(equation, 'x')
print("Réponse partie 2 (résolution équation par sympy):", ''.join(map(str, sols)))
print("\nSans sympy, copier l'équation dans une appli de maths:\n", equation+'=0')
# Merci quickmath, parce que wolframalpha trouve l'équation trop longue, à moins de passer par la page de résolution d'équation
import urllib.parse
print("ou ouvrir le lien suivant:\n https://quickmath.com/#" + urllib.parse.urlencode({'c':'mySolve','v1':equation+'=0','v3':'x'}))
print("ou ouvrir le lien suivant:\n https://www.wolframalpha.com/input?" + urllib.parse.urlencode({'i2d':'true','i':equation+'=0'}))