Suite de l'Avent du Code, jour 11.
Des singes ont volé le contenu de notre sac. Ils jouent à la passe à 10 avec. Pour récupérer le contenu, il faut identifier quel singes ont eu le plus d'items en main.
Un jour où la solution naïve permet de résoudre la partie 1 mais ne passe pas à l'échelle pour la partie 2.
# python, on oublie toute dignité
Posté par steph1978 . É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: python, on oublie toute dignité
Posté par GuieA_7 (site web personnel) . Évalué à 2.
sorted
renvoie déjà une liste: https://docs.python.org/3.8/library/functions.html#sorted[^] # Re: python, on oublie toute dignité
Posté par steph1978 . É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.
[^] # Re: python, on oublie toute dignité
Posté par GuieA_7 (site web personnel) . Évalué à 2.
Oui certainement, ça serait hypocrite de faire croire que la fonction arrive à travailler 'en flux' (sans tout charger) alors que ce n'est pas possible. Et derrière si tu veux un itérateur sur la liste retournée c'est très peu coûteux de te le faire (alors que le contraire est moins vrai).
[^] # Re: python, on oublie toute dignité
Posté par steph1978 . É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 :)
# À la chasse aux singes, j'envoie le Python !
Posté par Yth (Mastodon) . Évalué à 3.
Pour le « truc qui scale pas » de la seconde partie, un bug dans la première partie m'a fait tomber dessus très tôt, et la solution est assez simple.
Un mélange de propre et de hack tout moche pour celui-là, avec un affichage qui montre l'avancement des calculs, ya 9s pour la seconde partie tout de même…
L'idée pour la seconde passe c'est que tout peut se passer au modulo du produit de tous les modulos. Même au PGCM de tous les modulos des différents singes, mais le produit suffit, on a des nombres suffisamment petits pour que ça roule vite et bien.
Donc la première passe retourne ce produit des modulos, qui est nourri à la seconde passe, en modifiant la classe de base avant instanciation des nouveaux singes.
Joli hack bien crade quoi :)
Après on a quelques bidouilles d'affichage pour lister les singes et faire défiler le n° de round, et ainsi voir l'avancement des calculs.
Et bien sûr, le cœur du problème avec un bon gros
eval
sur l'opération à effectuer, sinon c'pas drôle ![^] # Re: À la chasse aux singes, j'envoie le Python !
Posté par 🚲 Tanguy Ortolo (site web personnel) . Évalué à 4.
Je n'ai pas encore résolu le problème de ce jour, dimanche c'est famille, mais ça va venir. 🙂
En lisant l'énoncé, tout de même, je m'étais dit que ça devait faire des nombres qui monteraient bien vite. En y réfléchissant, je pense que j'aurais tout seul pensé à travailler modulo leur PGCD.
Pour le code d'opération, l'eval vient tout de suite en tête bien sûr, mais ça me donne quand même quelques boutons, d'écrire du code qui a l'air d'un trou de sécurité. Réflexe professionnel je pense. À suivre, je dois toujours coder ça de toute façon.
[^] # Re: À la chasse aux singes, j'envoie le Python !
Posté par 🚲 Tanguy Ortolo (site web personnel) . Évalué à 3.
Euh, modulo leur PPCM évidemment !
[^] # Re: À la chasse aux singes, j'envoie le Python !
Posté par Yth (Mastodon) . Évalué à 2.
Ah oui, j'ai sorti l'eval avec réticence, mais c'est tellement adapté à ce cas précis…
Professionnellement il faudrait salement valider la chaîne, et probablement qu'un parseur aurait été la solution, pour ne pas faire d'eval.
[^] # Re: À la chasse aux singes, j'envoie le Python !
Posté par GuieA_7 (site web personnel) . Évalué à 4.
À noter que
str.join()
prend juste un itérable, et donc"\n".join([repr(m) for m in monkeys.values()])
peut s'écrire plus simplement"\n".join(repr(m) for m in monkeys.values())
.Même remarque avec
deque()
.# En Python, avec un parseur d'opération
Posté par 🚲 Tanguy Ortolo (site web personnel) . Évalué à 4.
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.