• [^] # Re: Commencer à représenter le problème pas trop bêtement.

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

    Alors avec plus d'abstraction, j'ai ça :

    from dataclasses import dataclass
    @dataclass(frozen=True)
    class Bag():
     red: int = 0
     green: int = 0
     blue: int = 0
     def __le__(self, other):
     if self.red > other.red or self.green > other.green or self.blue > other.blue:
     return False
     return True
     def __add__(self, other):
     return Bag(
     red=max(self.red, other.red),
     green=max(self.green, other.green),
     blue=max(self.blue, other.blue),
     )
     @property
     def power(self):
     return self.red * self.green * self.blue

    Une classe pour représenter un sac, avec des cubes rouges, verts et bleus dedans. La dataclass c'est bien pratique, ça s'initialise automatiquement avec les paramètres fournis aux noms des variables, ou alors aux valeurs par défaut.
    Par exemple Bag() c'est 0 de chaque, Bag(red=12, green=5), ça fait ce qui est écrit en laissant blue à 0.
    Il est frozen ce qui signifie qu'on ne peut pas le modifier, donc les opérations retournent une nouvelle instance de Bag, c'est utile en optimisation parce que ça va plus vite. Ici c'est sans importance.

    On définit trois opérations dessus : __le__ permet de comparer bag1 <= bag2, c'est True ssi tous les éléments de bag1 sont inférieurs ou égaux à ceux de bag2.
    __add__ c'est un peu un hack, et ça retourne un Bag avec le maximum pour chaque valeur dans les deux Bag additionnés, ça permet d'utiliser la fonction sum() pour calculer un maximum, parce que la fonction max() fait des comparaisons, et retourne le Bag en entrée le plus grand, ce qui n'a rien à voir avec ce dont on a besoin.
    Et finalement power est un attribut qui sert au calcul du score du second exercice.

    Avec cette classe on va analyser les données, en exploitant les passages d'arguments python par dictionnaire, et les valeurs par défaut de Bag, c'est pas trop abscons à lire, si on n'est pas débutant en Python (et qu'on aime les struct-comprehension) :

    def input():
     for line in sys.stdin:
     game, cubes = line.strip().split(':')
     yield int(game.split(" ")[1]), sum(
     (
     Bag(**{
     color: int(nb)
     for cubes in bag.strip().split(",")
     for nb, color in [cubes.strip().split(" ")]
     })
     for bag in cubes.split(";")
     ), Bag(),
     )

    En réalité on n'a jamais besoin des divers sacs possible, la seule chose qui nous intéresse c'est le maximum pour chaque valeur rouge, vert et bleu, d'où le sum(), et une fois cette optimisation faite, on réalise qu'on s'est furieusement compliqué la vie et qu'au final on avait juste besoin, depuis le tout début de l'exercice, de trouver ce maximum, et de ne s'intéresser qu'à lui.

    Les exercices ensuite sont triviaux, surtout le second, il n'y a vraiment plus rien à faire :

    datas = [x for x in input()]
    constraint = Bag(red=12, green=13, blue=14)
    r = sum(
     game
     for game, biggestbag in datas
     if biggestbag <= constraint
    )
    print(f"Possible games : {r}")
    power = sum(
     biggestbag.power
     for game, biggestbag in datas
    )
    print(f"Sum of Power of games : {power}")
    • Yth, qui vient de faire brûler un CPU sur l'exercice 5, parce que parfois c'est plus « rapide » de laisser turbiner que de trouver un meilleur algorithme, mais on en parle jour 5...