Parce que un truc de 351 * 175 dans le terminal c'est galère quand même...
Bref, j'ai perdu plein de temps à faire une animation pas trop lente (j'ai fini par exponentiellement sauter des images : j'affiche l'image 2n), et réussir à faire entrer ça proprement dans le terminal. Après coup j'ai réalisé qu'il suffisait d'afficher chaque grain de sable une fois calculé, au lieu de tout retracer... Dans un terminal... Diantre...
J'avais un bug débile aussi pour l'exo 2, comme je voulais un sol pas trop large pour l'affichage, j'ai essayé d'être intelligent, et ça n'a pas marché, j'ai fini par faire un affichage avec un sol pas très large, puis rajouter un sol très très large.
Après j'ai triché et j'ai juste mis le sol en dur aux bonnes dimensions pour tout afficher, une fois le résultat obtenu.
Deux belles images :
Premier exercice
Deuxième exercice
Et un code probablement trop complexe.
L'affichage déjà
classdisplay:sand=" "# "▒"sandcolor=220void=" "rock=" "# "█"rockcolor=94start="+"def__init__(self,x0,x1,y0,y1,*rocks):self.x0,self.x1,self.y0,self.y1=x0,x1,y0,y1self.bg=[[f"{self.color(bg=0)}{self.void}"forxinrange(x0,x1+1)]foryinrange(y0,y1+1)]forxinrocks:self.bg[x[1]-y0][x[0]-x0]=f"{self.color(bg=self.rockcolor)}{self.rock}"self.bg[0][500-x0]=self.startself.background="\n".join("".join(self.bg[y][x]forxinrange(len(self.bg[0])))foryinrange(len(self.bg)))self.width=len(self.bg[0])self.height=len(self.bg)defcolor(self,bg=None,fg=None,rgb=None):bg=f"033円[48;5;{bg}m"ifbgelse""fg=f"033円[38;5;{fg}m"iffgelse""fg=f"033円[38;2;{rgb[0]};{rgb[1]};{rgb[2]}m"ifrgbelsefgifnotbgandnotfg:return"033円[0m"returnf"{bg}{fg}"defcursor(self,row=0,col=0):ifrow<0:row=self.height-rowreturnf"033円[{row+1};{col+1}H"def__call__(self,*items,wait=0):print(self.str(items))ifwait:time.sleep(wait)defitem(self,item):return(f"{self.cursor(col=item[0]-self.x0, row=item[1]-self.y0)}"f"{self.color(bg=self.sandcolor)}"f"{self.sand}")if(item[0]>=self.x0anditem[0]<=self.x1anditem[1]>=self.y0anditem[1]<=self.y1)else""defstr(self,items):return(f"{self.cursor()}"f"{self.color()}"f"{self.background}"f"{''.join(self.item(item) for item in items)}")
Et le code en lui-même :
definput():forlineinsys.stdin:x=list(tuple(map(int,r.split(',')))forrinline.split(' -> '))for_inzip(x[:-1],x[1:]):yield_classRockFormation:def__init__(self,input):self.finished=Falseself.source=(500,0)self.carte=set()self.sand=set()for_ininput():self._add_rocks(*_)self.dim=self.calcdim(self.carte)self.rock=self.carte.copy()self.sand=set()def_add_rocks(self,r1,r2):x1=min(r1[0],r2[0])x2=max(r1[0],r2[0])y1=min(r1[1],r2[1])y2=max(r1[1],r2[1])self.carte.update((x,y)forxinrange(x1,x2+1)foryinrange(y1,y2+1))defadd_rocks(self,r1,r2):self._add_rocks(r1,r2)self.dim=self.calcdim(self.carte)self.rock=self.carte.copy()defcalcdim(self,carte):return(min(x[0]forxincarte),max(x[0]forxincarte),0,max(x[1]forxincarte),)def__call__(self):s=self._sand(*self.source)ifnotself.finished:ifsinself.carte:print(f"Re-adding {s} !")raiseIndexErrorself.carte.add(s)self.sand.add(s)ifs==self.source:self.finished=Truereturnsdef_sand(self,x,y):ifx<self.dim[0]orx>self.dim[1]ory==self.dim[3]:self.finished=Truereturnx,ywhile(x,y+1)notinself.carte:y+=1if(x-1,y+1)notinself.carte:x,y=self._sand(x-1,y+1)elif(x+1,y+1)notinself.carte:x,y=self._sand(x+1,y+1)returnx,ydefsimulation(rocks):d()whilerocks.finishedisFalse:print(d.item(rocks()))# Inputsrocks=RockFormation(input)# First simulationd=display(*rocks.dim,*rocks.rock)simulation(rocks)result1=len(rocks.sand)print(f"{d.cursor(row=-4)}{d.color()}Resting sand : {len(rocks.sand)}")# Second simulation preparationrocks.finished=False# Limited floor for display# rocks.add_rocks(# (rocks.dim[0]-1, rocks.dim[3]+2),# (rocks.dim[1]+1, rocks.dim[3]+2)# )# d = display(*rocks.dim, *rocks.rock)# # Big (not too huge) floor for simulation# rocks.add_rocks(# (rocks.dim[0]-1000, rocks.dim[3]),# (rocks.dim[1]+1000, rocks.dim[3])# )# Enough floor knowing the solutionrocks.add_rocks((325,174),(675,174))d=display(*rocks.dim,*rocks.rock)simulation(rocks)print(f"{d.cursor(row=-3)}{d.color()}",end='')print(f"Resting sand : {result1}")print(f"Filling sand : {len(rocks.sand)}")print(f"Dimensions 1 : {dim1}")print(f"Dimensions 2 : {rocks.dim}")display2=d.str(rocks.sand)# Et enfin afficher le résultat pour les screenshotsw,h=tuple(os.get_terminal_size())print("\n"*h)print(display1)print("\n"*h)print(display2)print(f"{d.cursor(row=-2)}{d.color()}",end='')
Il faut vachement zoomer arrière dans le terminal, après c'est écrit trop petit pour lire, mais on a une belle animation :)
# Beaucoup de temps pour animer et afficher joli
Posté par Yth (Mastodon) . En réponse au message Avent du Code, jour 14. Évalué à 4.
Parce que un truc de 351 * 175 dans le terminal c'est galère quand même...
Bref, j'ai perdu plein de temps à faire une animation pas trop lente (j'ai fini par exponentiellement sauter des images : j'affiche l'image 2n), et réussir à faire entrer ça proprement dans le terminal. Après coup j'ai réalisé qu'il suffisait d'afficher chaque grain de sable une fois calculé, au lieu de tout retracer... Dans un terminal... Diantre...
J'avais un bug débile aussi pour l'exo 2, comme je voulais un sol pas trop large pour l'affichage, j'ai essayé d'être intelligent, et ça n'a pas marché, j'ai fini par faire un affichage avec un sol pas très large, puis rajouter un sol très très large.
Après j'ai triché et j'ai juste mis le sol en dur aux bonnes dimensions pour tout afficher, une fois le résultat obtenu.
Deux belles images :
Premier exercice
Deuxième exercice
Et un code probablement trop complexe.
L'affichage déjà
Et le code en lui-même :
Il faut vachement zoomer arrière dans le terminal, après c'est écrit trop petit pour lire, mais on a une belle animation :)