Advent of code

 5 décembre 2023 

  If You Give A Seed A Fertilizer : Faire des correspondances de nombres sur de larges intervalles qui se chevauchent
seeds: 364807853 408612163 302918330
   
  
   
seed-to-soil map:
   
2069473506 3732587455 1483883
   
3235691256 2348990120 6550341
   
                  ⋮   
  
   
soil-to-fertilizer map:
   
2700214958 2743391193 363795571
   
                  ⋮   
humidity-to-location map:
   
                  
  1. code1.py
  2. code2.py
  3. code2_oo.py
  4. code2_oo_nonRecursif.py
  5. intervalle.py
class Intervalle():
    """ Représente un intervalle fini d'entiers semi-ouverts ⟦start;end⟦ = ⟦start;end-1⟧
        Mais on peut l'utiliser comme intervalles fermés (mais plus d'ensemble vide possible) """

    __slots__ = ['__tuple']
    
    def __init__(self, start: int, end: int):
        if end < start:
            raise ValueError(f"La fin de l'intervalle {end} ne peut pas être strictement plus petit que son début {start}.")
        self.__tuple = (start, end)
    @property
    def start(self):
        return self.__tuple[0]
    @property
    def end(self):
        return self.__tuple[1]
    
    def to_tuple(self):
        return self.__tuple
    
    def __str__(self) -> str:
        return f"⟦{self.start};{self.end}⟦"
    def __repr__(self) -> str:
        return self.__str__()
    def __eq__(self, other) -> bool:
        return self.to_tuple() == other.to_tuple()
    def __hash__(self) -> int:
        return self.to_tuple().__hash__()
    
    def __getitem__(self, index:int) -> int:
        if index in [0,1]:
            return self.__tuple[index]
        raise IndexError("index has to be 0 or 1")

    def __and__(self, other) -> "Intervalle":
        """ Intersection de deux intervalles """
        if self.start > other.start:
            return other.__and__(self)

        if self.est_vide() or other.est_vide() or self.end <= other.start:
            return Intervalle(0, 0)   # vide
        else:
            return Intervalle(other.start, min(self.end, other.end))
        
    def __sub__(self, other) -> list["Intervalle"]:
        """ Soustraction d'un intervalle à un autre """
        inters = self & other
        if inters.est_vide():
            return [self]
        if inters == self:
            return []
        if self.start == inters.start:
            return [Intervalle(inters.end, self.end)]
        elif self.end == inters.end:
            return [Intervalle(self.start, inters.start)]
        else:
            return [Intervalle(self.start, inters.start), Intervalle(inters.end, self.end)]
        
    def __contains__(self, valeur: int) -> bool:
        """ Pour utilisation du mot-clé «in»:  (2 in ⟦-3;4⟦ -> True)
            (pas utilisé dans ce problème, mais c'était trop cool pour passer à côté) """
        return self.start <= valeur < self.end
    
    def est_vide(self) -> bool:
        return self.start == self.end

    def decale(self, decalage: int) -> "Intervalle":
        return Intervalle(self.start + decalage, self.end + decalage)