Suite de l'Avent du Code, jour 10.
Le Père Noël est tombé dans un torrent et n'a pas bien entendu ce que les lutins ont voulu lui dire avant de continuer leur chemin. Pour trouver un moyen de communiquer avec eux, il faut réimplémenter le processeur de son communicateur, qui a un peu souffert de l'humidité.
# En Python, modélisé
Posté par 🚲 Tanguy Ortolo (site web personnel) . Évalué à 5. Dernière modification le 10 décembre 2022 à 13:03.
Sans surprise, j'ai implémenté un CPU selon les spécifications fournies. Mais pour ce qui est de faire quelque chose à partir des états qu'il atteint à des cycles donnés, je me suis amusé à y introduire ce que j'ai appelé un débogueur, je vous laisse découvrir ça.
# quick python
Posté par steph1978 . Évalué à 3.
Rien à voir avec hier, les deux parties en une grosse demie heure.
part 1
part 2
[^] # Re: quick python
Posté par Yth (Mastodon) . Évalué à 4. Dernière modification le 10 décembre 2022 à 15:14.
Tu peux simplifier un peu ta gestion des input en faisant ça :
Le premier point, d'utiliser
for l in sys.stdin
permet de ne pas lire tout l'input, mais simplement d'itérer sur les lignes, on reste plus bas en RAM, on traite un flux.Le second point, c'est d'utiliser *q pour prendre « ce qui reste ».
Dans le cas d'une ligne "noop" on a m="noop" et q=[].
Dans le cas de "addx XX" on a m="addx" et q=[XX], une list avec la valeur en premier (et unique) élément.
Mais en refilant *q à int, il « unpack » et int(*q) devient équivalent à int(XX).
Avec ça tu gères des instructions différentes, avec autant de paramètres que tu veux, tu t'en fous au niveau du parsing, tu veux juste connaître l'instruction et passer le reste à la gestion de l'instruction.
Ça évite de rajouter un argument factice, et de splitter en ne prenant que les deux premiers.
PS: et aussi, chapeau pour la maîtrise d'awk, j'en suis pas là !
[^] # Re: quick python
Posté par steph1978 . É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.
# Entre deux.
Posté par Yth (Mastodon) . Évalué à 3.
Moins modélisé que Tanguy, mais plus que steph.
Là je conserve tout l'historique des valeurs de X à chaque cycle, ça n'est évidemment pas viable sur un long programme.
Il faudrait optimiser pour la demande, c'est à dire écrire instruction après instruction l'état de l'écran pour le cycle qui passe, et faire un hook sur les valeurs de la première question, pour additionner/stocker par ailleurs.
Au début j'avais mis un compteur de cycle dans ma classe
cpu
mais à la fin je ne l'utilisais pas, alors je l'ai viré…C'est assez facile d' « optimiser » la classe cpu pour qu'elle dessine l'écran au fur et à mesure, on fait une méthode comme ça :
Et définir
self.col = 0; self.screen = []
dans l'init.On remplace les appels à
self.history.append(self.X)
parself.cycle()
.On réalise que
cpu.noop
ne fait plus qu'exécutercpu.cycle
, donc on gardenoop
etaddx
devient :On vire le
cpu.call
puisqu'on dessine l'écran à la volée dansmycpu.screen
et on afficheprint("".join(mycpu.screen))
à la fin. On n'a plus qu'à rajouter un history à 0 pour le cycle 0 inexistant, et on n'a plus besoin de fairereturn self.history[n-1]
danscpu.__getitem__()
Avec tout ça mis en place on a un code plus concis, plus clair, mais on conserve toujours l'historique pour la question 1, et s'en débarrasser oblige a faire un hook un peu crados dans
cpu.noop()
, conserver le numéro du cycle courant, et sicycle%40==20
ajouter àself.signal_strength
self.X * self.cycle
.On se débarrasse de l'historique.
Plus propre ?
Moins propre ?
Difficile à dire…
Mais il s'agit de débuggage, donc on peut introduire un hook cpu.debug à chaque cycle, qui servirait à ça.
Bilan :
Bilan ?
8 octets de différence dans le fichier final, temps d'exécution rigoureusement similaire.
En pratique si on bourrine sur les entrées, le second code est plus lent puisqu'il maintient à jour un écran.
On peut utiliser un deque pour cpu.screen et avoir un scroll automatique, ça restreint la RAM utilisée, qui reste stable quelles que soient les données en entrées.
Alors que le premier fait juste un history.append(), ça pompe de la RAM (à l'infini d'ailleurs) mais pas du CPU.
# Où est la partie 2 ?
Posté par gled . Évalué à 1.
Pour la somme des intensités, pas trop de difficultés, ma solution sans fioritures (en trichant un peu).
Mais que faut-il faire ensuite ? Où est la seconde partie de l'exercice sur la page d'adventofcode ? La dernière phrase que je vois sur la page est :
Faut-il avoir un compte susnommé en bas de page pour le voir ?
[^] # Re: Où est la partie 2 ?
Posté par Yth (Mastodon) . Évalué à 3.
Il faut te connecter, d'une façon ou d'une autre, j'utilise mon compte github perso.
Et là tu as un jeu de donnée personnalisées en entrée, et tu peux fournir le résultat dans un champs spécifique en bas de page.
Ça te donne accès au second exercice.
[^] # Re: Où est la partie 2 ?
Posté par 🚲 Tanguy Ortolo (site web personnel) . Évalué à 4.
Oui, la seconde partie apparaît alors avoir rentré la bonne réponse à la première partie. Et les données d'entrée et donc les bonnes réponses sont associées à une identité en effet.
[^] # Re: Où est la partie 2 ?
Posté par gled . Évalué à 1.
Ah d'accord, merci à vous deux, Yth et 🚲 Tanguy Ortolo de la confirmation, bien dommage alors.
# Plus simple
Posté par GaMa (site web personnel) . Évalué à 3.
J'ai trouvé ce jour assez facile.
J'ai pas modélisé un CPU complet comme Tanguy, c'est un peu l'enclume pour écraser la mouche.
L'astuce pour rester simple, c'est de remplacer une instruction add (sur deux cycles) par une instruction noop et une instruction add (sur un cycle). Après ça roule tout seul.
Matthieu Gautier|irc:starmad
[^] # Re: Plus simple
Posté par 🚲 Tanguy Ortolo (site web personnel) . Évalué à 3.
Ça reste à voir, ça. Il y a eu un AoC où on n'arrêtait pas de ressortir un processeur bizarroïde pour l'enrichir de nouvelles instructions et variantes d'instructions existantes.
Il y a un risque pour que ce ne soit pas la dernière fois que nous aurons à bidouiller avec du code machine de communicateur elfique…
[^] # Re: Plus simple
Posté par Yth (Mastodon) . Évalué à 2. Dernière modification le 10 décembre 2022 à 20:17.
C'est un peu l'idée derrière mon propre code.
Et si on l'enrichissait ?
Par exemple si on veut ajouter une commande
affxy a b
- qui fait la fonction affinea*x+b
- à deux arguments et trois cycles par exemple, dans mon code il suffit d'ajouter cette méthode :Voilà, c'est géré.
[^] # Re: Plus simple
Posté par steph1978 . Évalué à 3.
C'est l'AoC 2019 au moins un jour sur deux il fallait ressortir son processeur "intcode".
# un bout de AWK
Posté par steph1978 . É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: un bout de AWK
Posté par steph1978 . Évalué à 3.
Pour la partie deux, aucun intérêt à bufferiser avant d'afficher :
awk, 14 loc
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.