Jour 6 - opération bidouille

Advent of Code 2025

Adrien Foucart

2025-12-06

Retour à l’index

Puzzle: https://adventofcode.com/2025/day/6

Je n’ai pas trop aimé celui-ci, donc on va faire court. C’est principalement du bidouillage à faire sur les entrées pour les mettre dans le bon ordre, mais à part ça il n’y a pas trop à réfléchir.

On doit trouver la solution d’opérations mathématiques simples, mais dont les opérateurs et les opérandes sont arrangés un peu bizarrement.

123 328  51 64 
 45 64  387 23 
  6 98  215 314
*   +   *   +  

Pour la première partie, on applique l’opérateur sur tous les nombres de la colonne. Donc: 123*45*6, 328+64+98, etc. On doit ensuite calculer la somme de tous les résultats des opérations.

Première étape: séparer les lignes, et dans chaque ligne couper sur les espaces. La fonction split de Python est pratique pour ça, car par défaut elle coupe sur tout ce qui est “whitespace”: espace simple, espaces multiples, tabulations… Pas besoin donc d’une logique compliquée.

def prepare_data(data: str) -> list[tuple[str]]:
    table = [d.split() for d in data.split('\n')]
    # ...

À ce stade, on a un tableau à deux dimensions, mais on veut faire les opérations par colonne. Pour se faciliter la vie, on peut transposer le tableau pour que les colonnes deviennent des lignes, et vice-versa. Un truc rapide pour faire ça en Python est d’utiliser une combinaison de * (l’opérateur d’unpacking) et zip (pour parcourir plusieurs listes en parallèle):

def prepare_data(data: str) -> list[tuple[str]]:
    table = [d.split() for d in data.split('\n')]

    return list(zip(*table))

*table va séparer notre tableau en lignes (équivalent de faire table[0], table[1], ...), et zip va permettre de d’abord regarder le premier élément de chaque ligne, puis le second, etc. zip donne un générateur, qu’on reconvertit en list.

Après ça, on a: [('123', '45', '6', '*'), ('328', '64', '98', '+'), ('51', '387', '215', '*'), ('64', '23', '314', '+')], et nos opérandes sont bien rassemblés avec nos opérateurs, qui sont toujours le dernier élément de la liste. Pour effectuer les opérations, on sépare les opérandes et l’opérateur, et on peut utiliser functools.reduce pour appliquer cumulativement l’opérateur aux opérandes. Il nous faut juste convertir les string soit en entiers, soit en fonction:

fns = {
    '*': lambda x, y: x*y,
    '+': lambda x, y: x+y,
    '-': lambda x, y: x-y,
    '/': lambda x, y: x/y
}

def operate(op: tuple[str]) -> int:
    operands, operator = op[:-1], op[-1]
    return reduce(fns[operator], [int(x) for x in operands])

Et dans le main, on peut appliquer cette opération à chaque ligne de données, et sommer les résultats:

def main():
    data = load_input(6, '_sample', prepare_data)
    print(f"Part 1: {sum(operate(d) for d in data)}")

Pour la seconde partie, on doit lire les opérations un peu différemment. Maintenant, les nombres eux-mêmes sont écrits de haut en bas. Donc notre exemple:

123 328  51 64 
 45 64  387 23 
  6 98  215 314
*   +   *   +  

Doit maintenant se lire: 1*24*356, 369+248+8, etc.

On doit donc traiter les données un peu différemment. On récupère notre tableau en séparant tous les caractères, et pas sur les whitespace. On le transpose comme avant, et on supprime les espaces.

def prepare_data_2(data: str) -> list[str]:
    table = [[c for c in row] for row in data.split('\n')]
    table = list(zip(*table))
    table = [''.join(t).replace(' ', '') for t in table]
    return table

Ca nous donne une liste:

['1*', '24', '356', '', '369+', '248', '8', '', '32*', '581', '175', '', '623+', '431', '4']

Dans cette liste, on sait que chaque opération est séparée par un '', et contient l’opérateur à la fin d’un nombre. Dans l’exemple ici c’est à chaque fois le premier, mais je n’ai pas trop envie de vérifier que c’est le cas partout dans le vrai input, donc on va être un peu plus général:

def part2(data: list[str]) -> int:
    operands = []
    operator = None
    total = 0
    for s in data:
        if s == '':
            total += reduce(fns[operator], operands)
            operands = []
            operator = None
            continue
        if s[-1] in fns.keys():
            operator = s[-1]
            operands.append(int(s[:-1]))
        else:
            operands.append(int(s))
    total += reduce(fns[operator], operands)
    return total

Dès qu’on trouve un '', on applique l’opération sur les éléments précédents, qu’on convertit au fur et à mesure en opérandes entières et opérateurs. Dans le main:

def main():
    # ...
    data2 = load_input(6, '_sample', prepare_data_2)
    print(f"Part 2: {part2(data2)}")

Et on y est.

Solution sur codeberg