importsysdefinput():forlineinsys.stdin:yieldtuple(line.split())classcpu:def__init__(self):self.X=1self.history=[]defnoop(self):self.history.append(self.X)defaddx(self,n):self.history.append(self.X)self.history.append(self.X)self.X+=int(n)def__getitem__(self,n):# Cycle 1 is history 0returnself.history[n-1]def__call__(self,row,col):return"#"ifabs(self.history[row*40+col]-col)<=1else" "mycpu=cpu()foraction,*valuesininput():getattr(mycpu,action)(*values)signal_strength=sum(mycpu[n]*nforninrange(20,221,40))print(f"Signal Strength : {signal_strength}")screen="\n".join("".join(mycpu(row,col)forcolinrange(40))forrowinrange(6))print(screen)
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) par self.cycle().
On réalise que cpu.noop ne fait plus qu'exécuter cpu.cycle, donc on garde noop et addx devient :
On vire le cpu.call puisqu'on dessine l'écran à la volée dans mycpu.screen et on affiche print("".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 faire return self.history[n-1] dans cpu.__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 si cycle%40==20 ajouter à self.signal_strengthself.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 ?
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.
# Entre deux.
Posté par Yth (Mastodon) . En réponse au message Avent du Code, jour 10. É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
cpumais à 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.noopne fait plus qu'exécutercpu.cycle, donc on gardenoopetaddxdevient :On vire le
cpu.callpuisqu'on dessine l'écran à la volée dansmycpu.screenet 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==20ajouter àself.signal_strengthself.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.