• # On bourrine, on bourrine et on fait des bêtises...

    Posté par (Mastodon) . En réponse au message Advent of Code 2023 : Day 3. Évalué à 2.

    Faut dire, j'ai pu m'y mettre vers 23h30 hier soir...
    Et ma bêtise a été de transformer "927*741" en 927741 au lieu de 927 et 741 séparés.

    Déjà, la somme totale de tous les nombre du jeu se calcule ainsi :

    s = ".".join(x.strip() for x in sys.stdin)
    for i in set(x for x in s if x not in "0123456789"):
     s = s.replace(i, " ")
    all_numbers = sum(int(i) for i in s.split(" ") if i) # =598313

    Ce calcul fait à l'avance m'aurait permis de voir que 9691964 comme résultat, c'était ouvertement faux...

    Bref, j'ai commencé à chercher certaines optimisations, en utilisant des comparaisons de set() en python, qui sont plutôt efficaces. Et j'aurais probablement dû utiliser des frozenset, car c'est plus rapide, quand on n'a pas besoin de les modifier.
    Il reste aussi des optimisations faisables, mais la taille des données ne les justifient pas encore.

    Zéro structures de données, un traitement très linéaire, ça reste simple, on ne fait pas encore de réelles abstractions.

    import sys
    directions = ((-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 0), (0, 1), (1, -1), (1, 0), (1, 1))
    def envelope(positions):
     return set(
     tuple(sum(x) for x in zip(a, p))
     for p in positions
     for a in directions
     )
    numbers = list()
    symbols = set()
    gears = set()
    nl = 0
    for line in sys.stdin:
     number = []
     positions = set()
     nc = 0
     for c in line.strip():
     if c in "0123456789":
     number.append(c)
     positions.add((nl, nc))
     else:
     if c != ".":
     print(f"Symbol {c} at {nl}, {nc}")
     symbols.add((nl, nc))
     if c == "*":
     gears.add((nl, nc))
     if number:
     numbers.append((int("".join(number)), envelope(positions)))
     number = []
     positions = set()
     nc += 1
     if number:
     numbers.append((int("".join(number)), envelope(positions)))
     number = []
     positions = set()
     nl += 1

    numbers est la liste des nombres et de leur « enveloppe » c'est à dire des coordonnées de toutes les cases composant ce nombre et adjacentes à lui.
    C'est un set() de doublets.
    symbols contient la liste des coordonnées (doublets) de tous les symboles du plan.
    gears contient la liste des coordonnées des symboles * uniquement, et ne servira que pour la seconde partie.

    Je trouve le code un poil moche, et un meilleur travail sur les entrées, et les conditions boucles, pourrait alléger, mais il faut absolument ne pas se planter dans les cas limites : un nombre en fin de ligne, deux nombres séparés par un symbole (celui-là m'a mis dedans), etc.
    Être carré, clairs, précis, sinon c'est l'écran bleu... Euh, enfin, la mauvaise réponse quoi...

    La résolution des problèmes est assez simple après ça.
    Problème n°1 :

    result = list()
    nope = 0
    for number, pos in numbers:
     if symbols.intersection(pos):
     result.append(number)
     else:
     nope += number
    print(result)
    print(f"Sum of Numbers : {sum(result)} ({nope})")

    nope me sert à la validation, vu que j'ai la somme de tous ems chiffres qui vaut 598313, je dois avoir result + nope = 598313, et j'aurais pu aussi juste calculer nope et obtenir mon résultat comme ça, par soustraction.
    Ça pourra servir comme façon de faire plus tard, je me rappelle d'un exercice avec du sable qui s'écoule, qui peut se résoudre très facilement en regardant uniquement là où il ne s'écoule pas et en faisant une soustraction...

    Et le second challenge :

    gear_value = 0
    for gear in gears:
     parts = [
     number
     for number, pos in numbers
     if gear in pos
     ]
     if len(parts) == 2:
     gear_value += parts[0] * parts[1]
    print(f"Sum of NumbersGear Value : {gear_value})")

    Rien à recalculer, on va analyser dans l'autre sens : pour chaque « gear » on regarde dans combien de « number » il se trouve, si c'est 2, bingo, on l'ajoute.
    C'est tout.

    • Yth.