Ayé, j'ai résolu la partie 2. Mais je ne suis pas du tout satisfait de ma solution, c'est super efficace mais j'ai l'impression d'avoir triché.
Je vous explique. Pour la partie 1, j'ai écrit une fonction récursive qui donne le nombre de possibilités d'arrangements restants étant donné des choix déjà faits sur un certain nombre de sources. Elle prend en entrée un état d'avancement, qui indique :
l'état de fonctionnement de la dernière source considérée (fonctionnelle ou hors service, pas inconnue, comme on va le voir.) ;
la position de la dernière source considérée ;
l'index du groupe courant de sources hors service ;
le nombre de sources hors service actuellement comptabilisée dans le groupe courant.
Si on a considéré toutes les sources, ça renvoie directement 1 si le compte est bon (on a atteint le dernier groupe de sources cassées et il est exactement rempli) et 0 sinon.
Si on n'a pas encore considéré toutes les sources, ça regarde la suivante et ça itère sur ses états possibles (une source en état ne peut être qu'en état, une source cassée ne peut être que cassée et une source en état inconnu peut être les deux, évidemment) :
* pour un état hors service, si la dernière source considérée était en état, ça ouvre un nouveau groupe... si possible, c'est à dire s'il reste des groupes non considérés, sinon on est dans une impasse et ça continue ;
* pour un état en état (hmm...), si la dernière source considérée était hors service, ça vérifie si le compte de sources hors service correspond au groupe courant et si ce n'est pas le cas on est dans une impasse et ça continue ;
* dans les cas où on n'a pas continueé, on appelle la même fonction récursive pour l'étape d'après et on ajoute sa valeur de retour à celle qu'on va renvoyer.
Ce sera peut-être plus clair avec le code :
fromcollections.abcimportIterable,IteratorfromtypingimportOptional,SelffromenumimportEnumclassCondition(Enum):OPE='.'BRK='#'UNK='?'defstates(self)->Iterator[Self]:ifselfisself.OPE:yieldselfelifselfisself.BRK:yieldselfelse:yieldself.OPE# type: ignoreyieldself.BRK# type: ignoreclassCondition(Enum):OPE='.'BRK='#'UNK='?'defstates(self)->Iterator[Self]:ifselfisself.OPE:yieldselfelifselfisself.BRK:yieldselfelse:yieldself.OPE# type: ignoreyieldself.BRK# type: ignoredefarrangements(self)->int:defaux(condition:Condition,spring:int,group:int,count:int)->int:ifspring==len(self.springs)-1:# Last spring has just been accounted for, time to check:# - we are at last group;# - that group is full.if(group==len(self.groups)-1andcount==self.groups[-1]):return1return0# Some springs have not been checked yet.next_spring=spring+1next_group=groupnext_count=countpossibilities=0fornext_conditioninself.springs[next_spring].states():ifnext_conditionisCondition.BRK:ifconditionisCondition.OPE:# Broken spring after an operational one opens# new group... if possible.ifgroup==len(self.groups)-1:# Last group has already been checked and closed:# dead end.continue# We can open next groupnext_group+=1next_count=0# Regardless of previous spring condition, increase current# group count.next_count+=1ifnext_count>self.groups[next_group]:# New current group is overfull: dead end.continueifnext_conditionisCondition.OPE:ifconditionisCondition.BRK:# Operational spring after a broken one closes current# group, time to check group count.ifcount!=self.groups[group]:# Dead endcontinuepossibilities+=aux(next_condition,next_spring,next_group,next_count)returnpossibilitiesreturnaux(Condition.OPE,-1,-1,0)
Bon, pour la partie 2, c'est beaucoup trop long, évidemment. Et donc, faute de trouver une astuce, vu le genre de paramètres de la fonction, j'ai bêtement utilisé un...
[^] # Re: Rien de vraiment compliqué, il faut juste utiliser tout ce qu'on sait faire.
Posté par 🚲 Tanguy Ortolo (site web personnel) . En réponse au message Advent of Code 2023, jour 12. Évalué à 4. Dernière modification le 12 décembre 2023 à 13:51.
Ayé, j'ai résolu la partie 2. Mais je ne suis pas du tout satisfait de ma solution, c'est super efficace mais j'ai l'impression d'avoir triché.
Je vous explique. Pour la partie 1, j'ai écrit une fonction récursive qui donne le nombre de possibilités d'arrangements restants étant donné des choix déjà faits sur un certain nombre de sources. Elle prend en entrée un état d'avancement, qui indique :
Si on a considéré toutes les sources, ça renvoie directement 1 si le compte est bon (on a atteint le dernier groupe de sources cassées et il est exactement rempli) et 0 sinon.
Si on n'a pas encore considéré toutes les sources, ça regarde la suivante et ça itère sur ses états possibles (une source en état ne peut être qu'en état, une source cassée ne peut être que cassée et une source en état inconnu peut être les deux, évidemment) :
* pour un état hors service, si la dernière source considérée était en état, ça ouvre un nouveau groupe... si possible, c'est à dire s'il reste des groupes non considérés, sinon on est dans une impasse et ça
continue;* pour un état en état (hmm...), si la dernière source considérée était hors service, ça vérifie si le compte de sources hors service correspond au groupe courant et si ce n'est pas le cas on est dans une impasse et ça
continue;* dans les cas où on n'a pas
continueé, on appelle la même fonction récursive pour l'étape d'après et on ajoute sa valeur de retour à celle qu'on va renvoyer.Ce sera peut-être plus clair avec le code :
Bon, pour la partie 2, c'est beaucoup trop long, évidemment. Et donc, faute de trouver une astuce, vu le genre de paramètres de la fonction, j'ai bêtement utilisé un...