Advent of code

 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
   
        
  1. moncode.py
  2. codeReductionEquation.py
  3. calcul.py
class calcul:
    def __init__(self, t):
        if type(t) == calcul:
            self.type = t.type
            if t.type in ['i', 'x']:
                self.v = t.v
            else:
                self.m1 = t.m1
                self.m2 = t.m2
            return

        if (type(t) == list or type(t) == tuple) and len(t) == 1:
            t = t[0]
            
        if type(t) == int:
            self.type = 'i'
            self.v = t
        elif type(t) == str:
            self.type = 'x'
            self.v = t
        else:
            m1 = calcul(t[0])
            m2 = calcul(t[2])

            if m1.type == 'i' and m2.type == 'i' and (t[1] != '/' or m1.v % m2.v == 0):
                self.type = 'i'
                if t[1] == '+':
                    self.v = m1.v + m2.v
                elif t[1] == '-':
                    self.v = m1.v - m2.v
                elif t[1] == '*':
                    self.v = m1.v * m2.v
                elif t[1] == '/':
                    self.v = m1.v // m2.v
                else:
                    print("Aargh 2", t)
                    exit(1)
                if(self.v == 0):
                    print("Hum...", t, t[0], t[1], t[2])
            else:
                self.m1 = m1
                if t[1] not in ['+', '-', '*', '/']:
                    print("Aaargh 3", t, t[0], t[2])
                    exit(1)
                self.type = t[1]
                self.m2 = m2

    def isNum(self):
        return self.type == 'i' or set(str(self)).issubset(set('()+-*/ 0123456789'))    # pas de x ou autre variable

    def reduire(self):
        if self.type in ['i', 'x']:
            return self
        m1 = self.m1.reduire()
        m2 = self.m2.reduire()
        if m1.type == 'i' and m2.type == 'i':
            if self.type != '/' or m1.v % m2.v == 0:
                return calcul([m1, self.type, m2]).reduire()
            elif self.type == '/':
                v1 = m1.v
                v2 = m2.v
                if v2 < 0:
                    v1 *= -1
                    v2 *= -1
                for f in [2,3,5,7,11,13,17,19]:
                    while v1 % f == 0 and v2 % f == 0:
                        v1 //= f
                        v2 //= f
                m1.v = v1
                m2.v = v2

        if m2.type == 'i' and self.type in ['-']:
            return calcul([-m2.v, '+', m1]).reduire()


        if m2.isNum() and not m1.isNum() and self.type in ['+', '*']:
            return calcul([m2, self.type, m1]).reduire()
        if m2.type == 'i' and m1.type != 'i' and self.type in ['+', '*']:
            return calcul([m2, self.type, m1]).reduire()

        if self.type == '+':
            if m1.isNum() and m2.type in ['+', '-'] and m2.m1.isNum():
                return calcul([ [m1, '+', m2.m1], m2.type, m2.m2  ]).reduire()
            if m1.isNum() and m2.isNum():
                if m1.type == '/' and m2.type == '/':
                    return calcul([ [[m1.m1, '*', m2.m2], '+', [m2.m1, '*', m1.m2]], '/', [m1.m2, '*', m2.m2]  ]).reduire()
                elif m1.type == 'i':
                    return calcul([ [[m1.v, '*', m2.m2], '+', m2.m1], '/', m2.m2 ]).reduire()
        if self.type == '-':
            if m1.isNum() and m2.type in ['+'] and m2.m1.isNum():
                return calcul([ [m1, '-', m2.m1], '-', m2.m2  ]).reduire()
            if m1.isNum() and m2.type in ['-'] and m2.m1.isNum():
                return calcul([ [m1, '-', m2.m1], '+', m2.m2  ]).reduire()
            if m1.isNum() and m2.isNum():
                if m1.type == '/' and m2.type == '/':
                    return calcul([ [[m1.m1, '*', m2.m2], '-', [m2.m1, '*', m1.m2]], '/', [m1.m2, '*', m2.m2]  ]).reduire()
                elif m1.type == 'i':
                    return calcul([ [[m1.v, '*', m2.m2], '-', m2.m1], '/', m2.m2 ]).reduire()

        if self.type == '*':
            if m1.type == 'i' and m2.type in ['*', '/'] and m2.m1.type == 'i':
                return calcul([m1.v * m2.m1.v, m2.type, m2.m2]).reduire()
            if m1.type == 'i' and m2.type in ['/'] and m2.m2.type == 'i':
                return calcul([[m1, '/', m2.m2] , '*', m2.m1]).reduire()
            if m1.type == '*' and m2.type == '*':
                return calcul([ [m1.m1, '*', m2.m1], '*', [m1.m2, '*', m2.m2] ]).reduire()
            if m1.type == '/' and m2.type == '*':
                return calcul([ [m1.m1, '*', m2.m1], '*', [m2.m2, '/', m1.m2] ]).reduire()
            if m1.type == '*' and m2.type == '/':
                return calcul([ [m1.m1, '*', m2.m1], '*', [m1.m2, '/', m2.m2] ]).reduire()
            if m1.type == '/' and m2.type == '/':
                return calcul([ [m1.m1, '*', m2.m1], '/', [m1.m2, '*', m2.m2] ]).reduire()


        if self.type == '/':
            if m2.type == '/':
                return calcul( [m1, '*', [m2.m2, '/', m2.m1]] ).reduire()

            if m1.type == 'i' and m2.type == '*':
                if m2.m1.type == 'i' and m1.v % m2.m1.v == 0:
                    return calcul([m1.v // m2.m1.v, '/', m2.m2]).reduire()
                if m2.m1.isNum():
                    return calcul([[m1, '/', m2.m1], '/', m2.m2]).reduire()
            elif m1.type == 'i' and m2.type == '/':
                if m2.m1.type == 'i' and m1.v % m2.m1.v == 0:
                    return calcul([m1.v // m2.m1.v, '*', m2.m2]).reduire()
                if m2.m2.type == 'i':
                    return calcul([m1.v * m2.m2.v, '/', m2.m1]).reduire()
            elif m2.type == 'i' and m1.type in ['/']:
                return calcul([m1.m1, '/', [m2, '*', m1.m2]  ]).reduire()


            if m1.type == '/' and m2.type == '*':
                return calcul([m1.m1, '/', [m1.m2, '*', m2]]).reduire()
            if m1.type == '*' and m2.type == '/':
                return calcul([[m2.m2, '*', m1], '/', m2.m1]).reduire()
            if m1.type == '/' and m2.type == '/':
                return calcul([ [m1.m1, '*', m2.m2], '/', [m1.m2, '*', m2.m1] ]).reduire()
            if m1.type in ['*','/'] and m2.type == '*' and m1.m1.type == 'i' and m2.m1.type == 'i' and m1.m1.v % m2.m1.v == 0:   #  (a#f) / (b%g) = (a/b)
                return calcul([ [m1.m1.v // m2.m1.v, m1.type, m1.m2], '/', m2.m2 ]).reduire()


        if self.type == '*' and m2.type in ['+', '-']:
            return calcul([calcul([m1, '*', m2.m1]).reduire(), m2.type, calcul([m1, '*', m2.m2]).reduire()])
        if self.type == '/' and m1.type in ['+', '-']:
            return calcul([calcul([m1.m1, '/', m2]).reduire(), m1.type, calcul([m1.m2, '/', m2]).reduire()])


        c = calcul([m1, self.type, m2])
        if str(m1) == str(self.m1) and str(m2) == str(self.m2):
            return calcul([m1, self.type, m2])
        else:
            return calcul([m1, self.type, m2]).reduire()

    def __str__(self):
        if self.type == 'i':
            return str(self.v)
        if self.type == 'x':
            return self.v
        if self.type == '*':
            a = str(self.m1)
            b = str(self.m2)
            if self.m1.type not in ['*', '/', 'i', 'x']:
                a = '(' + a + ')'
            if self.m2.type not in ['*', '/', 'i', 'x']:
                b = '(' + b + ')'
            return a + '*' + b
        if self.type == '/':
            a = str(self.m1)
            b = str(self.m2)
            if self.m1.type not in ['*', '/', 'i', 'x']:
                a = '(' + a + ')'
            if self.m2.type not in ['i', 'x']:
                b = '(' + b + ')'
            return a + '/' + b
        if self.type == '+':
            return str(self.m1) + '+' + str(self.m2)
        if self.type == '-':
            a = str(self.m1)
            b = str(self.m2)
            if self.m2.type not in ['*', '/', 'i', 'x']:
                b = '(' + b + ')'
            return a + '-' + b