◂ 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:
⋮
- code1.py
- code2.py
- code2_oo.py
- code2_oo_nonRecursif.py
- intervalle.py
import re
f = open("input.txt", 'r', encoding='utf-8')
lines = [line[:-1] for line in f.readlines()]
def parse_ints(line: str) -> list[int]:
return [ int(tok) for tok in re.split('[^0-9]+', line) if tok ]
""" Pour les règles de transformations entre les différentes catégories
seed => soil => fertilizer => water => light => temperature => humidity => location """
Intervalle = tuple[int, int] # représente intervalle [a;b[ = [a;b-1] !
Regle = tuple[Intervalle, int] # intervalle [a;b[ qui s'applique, décalage
Transformation = list[Regle] # Règles pour passer d'une catégorie à la suivante
transformations: list[Transformation] = []
seeds = parse_ints(lines[0])
seeds_groupes_par_pairs = zip(* [iter(seeds)]*2 )
# ou: seeds_groupes_par_pairs = zip( seeds[0::2], seeds[1::2] )
# ou: seeds_groupes_par_pairs = itertools.batched(seeds,2) # idéal, mais depuis Python 3.12
seeds_intervalles: list[Intervalle] = [(a,a+d) for (a,d) in seeds_groupes_par_pairs]
# transformer la façon de décrire la règle dans input en une Regle plus lisible
def creer_regle(new_value_start: int, old_value_start: int, size: int) -> Regle:
intervalle_applique = (old_value_start, old_value_start + size)
decalage = new_value_start - old_value_start
return (intervalle_applique, decalage)
for line in lines[1:]:
if not line:
continue
elif ':' in line:
print("Lecture des règles de " + line.split()[0])
transformations.append([])
continue
else:
transformations[-1].append( creer_regle(*parse_ints(line)) )
def calc_valeur_suivante(regles: Transformation, intervalle: Intervalle) -> list[Intervalle]:
start, end = intervalle
for (a,b), decalage in regles:
# Si la règle ne s'applique pas ici: valeurs) s___e |
if start >= b or end <= a: # règle) | a_____b
continue
# Si la règle s'applique partout: valeurs) s___e
elif start >= a and end <= b: # règle) a_|___|____b
return [ (start + decalage, end + decalage) ]
# Si la règle s'applique sur une partie intérieure: v) s__|___|____e
elif start < a and end > b: # r) a___b
return calc_valeur_suivante(regles, (start, a)) \
+ [ (a + decalage, b + decalage) ] \
+ calc_valeur_suivante(regles, (b, end))
# Si la règle s'applique sur un bout à droite: v) s____|___e
elif start < a: # et donc on sait que end <= b r) a___|___b
return calc_valeur_suivante(regles, (start, a)) + [ (a + decalage, end + decalage) ]
# Sinon, la règle s'applique sur un bout à gauche: v) s___|____e
else: # r) a___|___b
return [ (start + decalage, b + decalage) ] + calc_valeur_suivante(regles, (b, end))
# Aucune règle ne s'est appliquée
return [ (start, end) ]
def calculer_intervalles_suivants(regles: Transformation, intervalles: list[Intervalle]) -> list[Intervalle]:
nouveaux_intervalles = []
for intervalle in intervalles:
nouveaux_intervalles.extend(calc_valeur_suivante(regles, intervalle))
return nouveaux_intervalles
intervalles = seeds_intervalles
for regles in transformations:
intervalles = calculer_intervalles_suivants(regles, intervalles)
print("Reponse partie 2:", min(a for (a,b) in intervalles))