Le parsing de l'input est presque plus long à écrire que l'application de règles : 4 boucles for imbriquées et 4 split contre 3 boucles while imbriquées.
Voici mon code pour la partie deux. La partie est identique excepté la condition de sortie.
importsysW=1000H=200L=[[0for_inrange(W)]for_inrange(H)]# full or airdefs2li(s,sep=','):returnlist(map(int,s.split(sep)))MAX_Y=0forlinsys.stdin.read().splitlines():lp=l.split(" -> ")forf,tinzip(lp,lp[1:]):(a,b,c,d)=(*s2li(f),*s2li(t))x0=min(a,c)y0=min(b,d)x1=max(a,c)y1=max(b,d)MAX_Y=max(MAX_Y,y1)forxinrange(x0,x1+1):foryinrange(y0,y1+1):L[y][x]=1forxinrange(W):L[MAX_Y+2][x]=1# rock on the groundstop=FalseN=0whilenotstop:N+=1y=0x=500more=True# can all left or right whilemoreandnotstop:more=FalsewhileL[y][x]==0:#and not stop: # if only airy+=1stop=y==MAX_Y+2ifL[y][x-1]==0:# can fall leftx-=1more=TrueelifL[y][x+1]==0:# can fall rightx+=1more=Trueelse:stop=y==1# can't put more sandL[y-1][x]=2# mark sandprint(N)
Et une jolie nimage de la caverne remplie de sable:
Posté par steph1978 .
En réponse au message Avent du Code, jour 13.
Évalué à 2.
Dernière modification le 13 décembre 2022 à 15:33.
Tu veux dire à la place du eval. Oui clairement, c'est moins craignos.
À la première lecture je pensais que tu voulais résoudre le problème en javascript 😓. Je veux dire juste en comparant les deux listes avec un <. J'ai tenté, ça marche presque 😛. Mais non en fait, les règles de comparaisons ne sont pas les mêmes.
Je galérais à organiser ma comparaison de paquets, et j'ai eu un indice d'utiliser un comparateur. Je suis reparti là dessus et ça fonctionne.
importsysP=[tuple(map(eval,p.split("\n")))forpinsys.stdin.read().split("\n\n")]defC(l,r):T=(type(l),type(r))ifT==(int,int):ifl<r:return-1returnl>r# 0 or 1ifT==(int,list):returnC([l],r)ifT==(list,int):returnC(l,[r])# list,listforqinzip(l,r):c=C(*q)ifc:returncreturnC(len(l),len(r))# part 1S=0fori,pinenumerate(P):ifC(*p)<=0:S+=i+1print(S)# part 2fromfunctoolsimportcmp_to_keyQ=[qfor(l,r)inPforqin[l,r]]Q.append([[2]])Q.append([[6]])Q.sort(key=cmp_to_key(C))print((Q.index([[2]])+1)*(Q.index([[6]])+1))
Dans mon input, tous les b ne sont que dans la deuxième colonne. Et la première colone ne contient que des a. Comme il faut nécessairement passer par un b, je n'ai testé que des départs depuis la première colonne.
J'ai passé plusieurs heures à ne pas comprendre pourquoi je ne trouvais pas la solution. Et puis j'ai compris ; j'ai loupé une phrase cruciale dans l'énoncée : on a le droit de redescendre, bordel !
J'ai utilise la très précieuse bibliothèque de manipulation de graph en Python, networkx. Mon code ne fait que parser l'input et construire la liste de transitions possibles et présente donc peu d'intérêt. Mais permet au moins de faire une joli nimage du résultat:
Si vous vous baladez sur Reddit, y en a qui ont fait des représentations de ouf.
La seconde partie était triviale dans ces conditions et m'a pris moins de deux minutes.
Posté par steph1978 .
En réponse au message Avent du Code, jour 11.
Évalué à 2.
Dernière modification le 11 décembre 2022 à 14:13.
Mince alors, toute une matinée de code à mettre à la benne 😩
Blague à part, merci pour la remarque, je confonds probablement avec map ou reversed qui retournent un itérateur.
J'imagine que pour trier, il faut charger toutes les données, donc pas d'intérêt de retourner un itérateur. Ou alors ne pas chercher d'explication, l'API python n'est pas toujours cohérente.
Posté par steph1978 .
En réponse au message Avent du Code, jour 11.
Évalué à 3.
Dernière modification le 11 décembre 2022 à 13:39.
Je suis tombé dans le piège de la solution qui ne scale pas en deuxième partie. Pas grave, on s'adapte.
Pour les deux parties, pour éviter un parsing laborieux, j'ai transformé l'input en code. Car à bien y regarder, c'est du code :)
La solution naïve ne scale pas car passé une certaine taille (32bit je crois) l'arithmétique des grands entiers sort du processeur, doit repasser par la mémoire et devient très très lente.
Chez moi c'était très net : les 500 premiers rounds sont fulgurants, moins de 1s, puis chaque round prends presque une seconde. Pour faire les 100000, en admettant avoir assez de RAM, il faudrait donc une grosse heure à 100% de CPU. Je n'ai pas cette patience.
L'astuce pour passer à l'échelle est de limiter la taille des nombres manipulés en appliquant l'arithmétique modulaire. Chaque singe à son diviseur (un nombre premier mais je crois pas que ça joue). Donc au lieu d'avoir l'item sous forme de nombre, on le transforme en une liste de restes de division, un pour chaque singe.
part 1
Je vous épargne le code complet de la première partie qui est en gros celui de la deuxième partie en un peu plus simple.
input
fromcollectionsimportdequeM=[(deque([84,72,58,51]),lambdaold:old*3,lambdax:7ifdivmod(x,13)[1]else1)# ...# same for all monkeys# ...]
part 2
input
fromcollectionsimportdequePRIMES=(13,2,7,17,5,11,3,19)defmods(x):return[x%iforiinPRIMES]M=[[deque(mods(x)forxin[84,72,58,51]),lambdaold:[((o%i)*(3%i))%ifor(o,i)inzip(old,PRIMES)],lambdax:7ifx[0]else1,0],[deque(mods(x)forxin[88,58,58]),lambdaold:[((o%i)+(8%i))%ifor(o,i)inzip(old,PRIMES)],lambdax:5ifx[1]else7,0]# ...# same for all monkeys# ...]
Je me moque gentiment. Tu as affiché clairement ton envie de faire du code propre, modélisé, typé. Et c'est louable.
Moi je pense avoir affiché mon objectif : peut importe le moyen pourvu qu'on ait la réponse le plus vite possible :)
J'ai réutilisé l'idée de l'utf8 pour le jour 10 aussi. La lecture du LCD est infiniment plus facile, plus besoin de plisser les yeux pour deviner les lettres.
Pour l'animation de la corde j'ai choisis d'afficher le numéro du noeud (0 à 9) en noir sur fond jaune ; et de déplacer la caméra de 19 d'un coup. J'aimais pas trop la voir manger le mur :). J'ai aussi géré les largeurs impaires, c'est le cas de mon terminal.
classdisplay:def__init__(self):self.w,self.h=tuple(os.get_terminal_size())border="o"self.delta=numpy.array((self.w//2,self.h//2))top=border*(self.w)wodd=self.w%2lines=[border+"░ "*(self.w//2-1)+"░"*wodd+border,border+" ░"*(self.w//2-1)+" "*wodd+border]self.background=[top+"".join(lines[h%2]forhinrange(self.h-2))+top,top+"".join(lines[1-h%2]forhinrange(self.h-2))+top]def__call__(self,knots):print("\033[0;0H",end='')x,y=self.delta+knots[0]J=19# must be odd to see scrollifx<=0:self.delta[0]+=Jifx>=self.w-1:self.delta[0]-=Jify<=0:self.delta[1]+=Jify>=self.h-1:self.delta[1]-=Jtxt=[cforcinself.background[sum(self.delta)%2]]fori,knotinenumerate(reversed(knots)):x,y=knot+self.deltatxt[int(x+y*self.w)]="\033[30;43m"+str(9-i)+"\033[0m"print("".join(txt),end='')time.sleep(.008)
Pour limiter les glitches, j'ai ajouté print("\033[0;0H", end='') au début du __call__.
Ça replace le curseur la coordonnée (0,0) du terminal ce qui évite le scrolling.
Dans la même veine, il est bénéfique de cacher le curseur avec tput civis avant de lancer l'animation. À la fin de l'animation, le remettre avec tput cnorm
J'ai fait la première partie en AWK en une petite demie heure.
J'ai eu pas mal de chance car mes calculs étaient approximatifs mais suffisant pour le cas à un noeud.
En voyant la seconde partie, j'ai tout ré-écrit en python car j'y ai vu un truc récursif.
J'ai pigé assez vite qu'il fallait mieux faire toutes les étapes, case par case pour tous les neouds.
Ça donnait toujours le bon résultat pour le premier noeud mais pas pour le dernier.
J'ai mis vraiment beaucoup de temps à débugger en pas à pas et ajuster mes calculs. Plusieurs heures :(
Pour au final un code très impératif que j'aurai presque pu laisser en AWK.
Posté par steph1978 .
En réponse au message Avent du Code, jour 8.
Évalué à 2.
Dernière modification le 08 décembre 2022 à 15:43.
Tu as eu une meilleure approche pour le première partie en effet. Il vaut mieux considérer les bords (N2) que toute les position de la grille (N3).
En pratique all va s'arrêter au premier False, ce qui fait que les chronos sont assez poche (0:33 pour les deux). Aussi parce que N est petit (N=99) et que lancer l'interpréteur est incompressible. Mais en théorie, c'est bien meilleur.
Même méthode pour les deux parties : un parcours de chaque position d'une matrice. Pour chaque position, regarder à gauche, à droite, en haut, en bas. Ça donne pas un code très beau mais ça marche.
C'est vrai que rien n'empêche de repasser deux fois pas le mm endroit pour pousser l'exploration des répertoires. Mais en effet c'est tordu et je n'avais pas de raison de me protéger "à prirori" de ce cas de figure. Si je n'étais pas parvenu à passer le test et la première partie, j'aurai regardé d'un peu plus près pour voir si des commandes cd child ne se répetent pas.
n'allons pas prétendre que tout est devenu nickel en la matière.
Non en effet. Mais je pense que la balance a penché côté linux en terme de matériel supporté, en particulier quand tu veux prolonger un ordinateur qui a plus de 5 ans.
En fait vu la structure de l'input où il n'y a que de cd child et cd .. # parent, c'est nécessairement un parcours d'arbre en profondeur d'abord. Il n'y a pas d'autres représentations de la relation parent-enfants, genre cd /chemin/absolu en aléatoire.
Et puis je préfère faire un code simple, le valider sur l'exemple, voire cramer un essai, avant de compliquer le code.
# python, vite fait bien fait
Posté par steph1978 . En réponse au message Avent du Code, jour 14. Évalué à 4.
Le parsing de l'input est presque plus long à écrire que l'application de règles : 4 boucles
for
imbriquées et 4split
contre 3 boucleswhile
imbriquées.Voici mon code pour la partie deux. La partie est identique excepté la condition de sortie.
Et une jolie nimage de la caverne remplie de sable:
[^] # Re: Étoile
Posté par steph1978 . En réponse au message Avent du Code, jour 12. Évalué à 2.
j'ai la même mais avec une rotation.
[^] # Re: python, en trichant
Posté par steph1978 . En réponse au message Avent du Code, jour 13. Évalué à 2. Dernière modification le 13 décembre 2022 à 15:33.
Tu veux dire à la place du eval. Oui clairement, c'est moins craignos.
À la première lecture je pensais que tu voulais résoudre le problème en javascript 😓. Je veux dire juste en comparant les deux listes avec un
<
. J'ai tenté, ça marche presque 😛. Mais non en fait, les règles de comparaisons ne sont pas les mêmes.# python, en trichant
Posté par steph1978 . En réponse au message Avent du Code, jour 13. Évalué à 4.
Je galérais à organiser ma comparaison de paquets, et j'ai eu un indice d'utiliser un comparateur. Je suis reparti là dessus et ça fonctionne.
[^] # Re: En Python
Posté par steph1978 . En réponse au message Avent du Code, jour 12. Évalué à 2.
Dans mon input, tous les b ne sont que dans la deuxième colonne. Et la première colone ne contient que des a. Comme il faut nécessairement passer par un b, je n'ai testé que des départs depuis la première colonne.
# python et lib de graph
Posté par steph1978 . En réponse au message Avent du Code, jour 12. Évalué à 4.
J'ai passé plusieurs heures à ne pas comprendre pourquoi je ne trouvais pas la solution. Et puis j'ai compris ; j'ai loupé une phrase cruciale dans l'énoncée : on a le droit de redescendre, bordel !
J'ai utilise la très précieuse bibliothèque de manipulation de graph en Python, networkx. Mon code ne fait que parser l'input et construire la liste de transitions possibles et présente donc peu d'intérêt. Mais permet au moins de faire une joli nimage du résultat:
Si vous vous baladez sur Reddit, y en a qui ont fait des représentations de ouf.
La seconde partie était triviale dans ces conditions et m'a pris moins de deux minutes.
# empaquetage
Posté par steph1978 . En réponse au journal Offpunk 1.8. Évalué à 4.
J'ai fait l'empaquetage avec pyinstaller. Ça semble bien fonctionner. Ça donne un exe autoporteur (interpréteur python compris) de 26MB.
Un simple
pip install pyinstaller && pyinstaller -F -n offpunk offpunk.py
suffit.Avec la possibilité de mettre l'exe dans les releases.
Peut être une façon de simplifier l'installation pour certains utilisateurs.
[^] # Re: python, on oublie toute dignité
Posté par steph1978 . En réponse au message Avent du Code, jour 11. Évalué à 2.
En poussant un peu plus la réflexion sur l’arithmétique modulaire, on peut se passer de balader des listes et garder un nombre. Trop tard pour moi :)
# un bout de AWK
Posté par steph1978 . En réponse au message Avent du Code, jour 10. Évalué à 4.
Je me suis laissé emporté par le python du jour 9.
Le problème du jour passe très bien en AWK.
part 1, 11 lines
part 2, 20 lines
[^] # Re: python, on oublie toute dignité
Posté par steph1978 . En réponse au message Avent du Code, jour 11. Évalué à 2. Dernière modification le 11 décembre 2022 à 14:13.
Mince alors, toute une matinée de code à mettre à la benne 😩
Blague à part, merci pour la remarque, je confonds probablement avec
map
oureversed
qui retournent un itérateur.J'imagine que pour trier, il faut charger toutes les données, donc pas d'intérêt de retourner un itérateur. Ou alors ne pas chercher d'explication, l'API python n'est pas toujours cohérente.
# python, on oublie toute dignité
Posté par steph1978 . En réponse au message Avent du Code, jour 11. Évalué à 3. Dernière modification le 11 décembre 2022 à 13:39.
Je suis tombé dans le piège de la solution qui ne scale pas en deuxième partie. Pas grave, on s'adapte.
Pour les deux parties, pour éviter un parsing laborieux, j'ai transformé l'input en code. Car à bien y regarder, c'est du code :)
La solution naïve ne scale pas car passé une certaine taille (32bit je crois) l'arithmétique des grands entiers sort du processeur, doit repasser par la mémoire et devient très très lente.
Chez moi c'était très net : les 500 premiers rounds sont fulgurants, moins de 1s, puis chaque round prends presque une seconde. Pour faire les 100000, en admettant avoir assez de RAM, il faudrait donc une grosse heure à 100% de CPU. Je n'ai pas cette patience.
L'astuce pour passer à l'échelle est de limiter la taille des nombres manipulés en appliquant l'arithmétique modulaire. Chaque singe à son diviseur (un nombre premier mais je crois pas que ça joue). Donc au lieu d'avoir l'item sous forme de nombre, on le transforme en une liste de restes de division, un pour chaque singe.
part 1
Je vous épargne le code complet de la première partie qui est en gros celui de la deuxième partie en un peu plus simple.
input
part 2
input
main loop
[^] # Re: En Python, modélisé
Posté par steph1978 . En réponse au message Avent du Code, jour 9. Évalué à 2.
Je me moque gentiment. Tu as affiché clairement ton envie de faire du code propre, modélisé, typé. Et c'est louable.
Moi je pense avoir affiché mon objectif : peut importe le moyen pourvu qu'on ait la réponse le plus vite possible :)
[^] # Re: En Python, modélisé
Posté par steph1978 . En réponse au message Avent du Code, jour 9. Évalué à 2.
Ah exacte, ligne 1527 et 1529 de son programme 😇
[^] # Re: En Python, modélisé
Posté par steph1978 . En réponse au message Avent du Code, jour 9. Évalué à 2.
Splendide !
J'ai réutilisé l'idée de l'utf8 pour le jour 10 aussi. La lecture du LCD est infiniment plus facile, plus besoin de plisser les yeux pour deviner les lettres.
Pour l'animation de la corde j'ai choisis d'afficher le numéro du noeud (0 à 9) en noir sur fond jaune ; et de déplacer la caméra de 19 d'un coup. J'aimais pas trop la voir manger le mur :). J'ai aussi géré les largeurs impaires, c'est le cas de mon terminal.
[^] # Re: Plus simple
Posté par steph1978 . En réponse au message Avent du Code, jour 10. Évalué à 3.
C'est l'AoC 2019 au moins un jour sur deux il fallait ressortir son processeur "intcode".
[^] # Re: En Python, modélisé
Posté par steph1978 . En réponse au message Avent du Code, jour 9. Évalué à 3.
J'adore l'animation !
Pour limiter les glitches, j'ai ajouté
print("\033[0;0H", end='')
au début du__call__
.Ça replace le curseur la coordonnée (0,0) du terminal ce qui évite le scrolling.
Dans la même veine, il est bénéfique de cacher le curseur avec
tput civis
avant de lancer l'animation. À la fin de l'animation, le remettre avectput cnorm
[^] # Re: quick python
Posté par steph1978 . En réponse au message Avent du Code, jour 10. Évalué à 3.
Ah ça c'est vu que j'ai bidouillé pour gérer un ou deux arguments par lignes :)
Merci pour l'astuce, ça me resservira.
# quick python
Posté par steph1978 . En réponse au message Avent du Code, jour 10. Évalué à 3.
Rien à voir avec hier, les deux parties en une grosse demie heure.
part 1
part 2
# pfiu
Posté par steph1978 . En réponse au message Avent du Code, jour 9. Évalué à 3.
J'ai fait la première partie en AWK en une petite demie heure.
J'ai eu pas mal de chance car mes calculs étaient approximatifs mais suffisant pour le cas à un noeud.
En voyant la seconde partie, j'ai tout ré-écrit en python car j'y ai vu un truc récursif.
J'ai pigé assez vite qu'il fallait mieux faire toutes les étapes, case par case pour tous les neouds.
Ça donnait toujours le bon résultat pour le premier noeud mais pas pour le dernier.
J'ai mis vraiment beaucoup de temps à débugger en pas à pas et ajuster mes calculs. Plusieurs heures :(
Pour au final un code très impératif que j'aurai presque pu laisser en AWK.
Bref dur ce jour pour moi
part 1
part 2
[^] # Re: python procédural, moche mais efficace
Posté par steph1978 . En réponse au message Avent du Code, jour 8. Évalué à 2. Dernière modification le 08 décembre 2022 à 15:43.
Tu as eu une meilleure approche pour le première partie en effet. Il vaut mieux considérer les bords (N2) que toute les position de la grille (N3).
En pratique
all
va s'arrêter au premierFalse
, ce qui fait que les chronos sont assez poche (0:33 pour les deux). Aussi parce que N est petit (N=99) et que lancer l'interpréteur est incompressible. Mais en théorie, c'est bien meilleur.# python procédural, moche mais efficace
Posté par steph1978 . En réponse au message Avent du Code, jour 8. Évalué à 3.
Même méthode pour les deux parties : un parcours de chaque position d'une matrice. Pour chaque position, regarder à gauche, à droite, en haut, en bas. Ça donne pas un code très beau mais ça marche.
part 1
part 2
Encore plus moche car le code à répéter quatre fois est plus long.
[^] # Re: Procrastination
Posté par steph1978 . En réponse au message Avent du Code, jour 7. Évalué à 4.
Toi t'as envie de ressortir quelques algos de parcours de graphes :) Dijkstra sort de ce corps!
[^] # Re: un bout de AWK
Posté par steph1978 . En réponse au message Avent du Code, jour 7. Évalué à 2.
C'est vrai que rien n'empêche de repasser deux fois pas le mm endroit pour pousser l'exploration des répertoires. Mais en effet c'est tordu et je n'avais pas de raison de me protéger "à prirori" de ce cas de figure. Si je n'étais pas parvenu à passer le test et la première partie, j'aurai regardé d'un peu plus près pour voir si des commandes
cd child
ne se répetent pas.[^] # Re: Souveraineté ?
Posté par steph1978 . En réponse au lien Le premier smartphone fabriqué en France arrive en 2024. Évalué à 4.
Non en effet. Mais je pense que la balance a penché côté linux en terme de matériel supporté, en particulier quand tu veux prolonger un ordinateur qui a plus de 5 ans.
[^] # Re: un bout de AWK
Posté par steph1978 . En réponse au message Avent du Code, jour 7. Évalué à 3.
En fait vu la structure de l'input où il n'y a que de
cd child
etcd .. # parent
, c'est nécessairement un parcours d'arbre en profondeur d'abord. Il n'y a pas d'autres représentations de la relation parent-enfants, genrecd /chemin/absolu
en aléatoire.Et puis je préfère faire un code simple, le valider sur l'exemple, voire cramer un essai, avant de compliquer le code.