Aller au contenu

Labyrinthe et algorithme de Kruskal⚓︎

On souhaite dans cet exercice dessiner des labyrinthes rectangulaires :

📋 Texte
 ___________________
|       | |  ____  _|
| | |_|__  _| |__  _|
|_|  _|____ |__  __ |
|_________|___|_|___|

Un labyrinthe sera représenté en machine par une liste de listes Python. Dans la liste lab, pour chaque couple de coordonnées (i, j), lab[i][j] sera un objet de type Cellule possédant trois attributs :

  • un booléen est indiquant si le mur à l'est de cette cellule est présent ou non (True par défaut),
  • un booléen sud indiquant si le mur au sud de cette cellule est présent ou non (True par défaut),
  • un entier zone donnant la zone à laquelle appartient cette cellule. Deux cellules sont dans la même zone s'il existe un chemin menant de l'une à l'autre dans le labyrinthe.

Remarque

Les cellules n'ont que deux murs et pas quatre afin d'éviter les doublons (le mur au sud d'une cellule pourrait correspondre au mur au nord de la cellule du dessous...).

Lors du dessin du labyrinthe, les murs au nord de la première ligne et à l'ouest de la première colonne seront dessinés par défaut.

🐍 Script Python
class Cellule:
    def __init__(self, zone):
        self.est = True
        self.sud = True
        self.zone = zone

La fonction base_labyrinthe permet de créer un labyrinthe dont tous les murs sont pleins. Elle prend en argument deux entiers strictement positifs, la hauteur hauteur et la largeur largeur du labyrinthe.

🐍 Script Python
def base_labyrinthe(hauteur, largeur):
    lab = []
    for i in range(hauteur):
        ligne = [Cellule(i * largeur + j) for j in range(largeur)]
        lab.append(ligne)
    return lab

Initialement, chaque cellule du labyrinthe est fermée sur elle-même : toutes les cellules sont donc initialement dans des zones différentes.

On peut accéder aux différentes cellules en procédant ainsi :

🐍 Console Python
>>> # Création de la base d'un labyrinthe de hauteur 4 et largeur 10
>>> lab = base_labyrinthe(4, 10)
>>> # Le mur à l'est de la cellule en haut à gauche est présent
>>> lab[0][0].est
True
>>> # La cellule de la 3ème ligne, 8ème colonne est dans la zone 26
>>> lab[2][7].zone
26

La fonction dessin_console renvoie la chaîne de caractères représentant le labyrinthe passé en argument :

🐍 Console Python
>>> print(dessin_console(lab))
 ___________________
|_|_|_|_|_|_|_|_|_|_|
|_|_|_|_|_|_|_|_|_|_|
|_|_|_|_|_|_|_|_|_|_|
|_|_|_|_|_|_|_|_|_|_|

Une variante de l'algorithme de Kruskal permet de construire des labyrinthes dans lesquels toutes les cellules appartiennent à la même zone et ne comportant pas de « boucles ».

On débute avec un labyrinthe dans lequel tous les murs sont présents. Au fil du traitement, on retire des murs de façon à fusionner des zones distinctes.

Les étapes de l'algorithme sont les suivantes :

  • créer un labyrinthe dans lequel tous les murs sont présents ;
  • créer la liste de tous les murs ;
  • mélanger cette liste ;
  • récupérer (et supprimer) le dernier mur de la liste jusqu'à ce qu'elle soit vide :
    • si ce mur sépare deux cellules de la même zone, ne rien faire,
    • s'il sépare deux cellules de zones différentes :
      • supprimer ce mur,
      • fusionner les zones correspondantes.

La dernière étape est importante : il faut non seulement faire en sorte que les deux cellules séparées par le mur soient dans la même zone mais aussi toutes les cellules communicantes. Ainsi, si l'on supprime un mur entre une zone de 5 cellules et une autre de 3 cellules, on obtiendra une nouvelle zone de 8 cellules.

La figure ci-dessous illustre la fusion de plusieurs zones (la construction du labyrinthe n'est pas terminée à la fin de l'animation).

Fusion de zones

La fonction murs_aleatoires prend en argument les dimensions du labyrinthe (hauteur et largeur) et renvoie la liste mélangée de ses murs sous la forme d'une liste de triplets (i, j, orientation). Le triplet (2, 7, "est") désignera par exemple le mur à l'est de la cellule de coordonnées (2, 7).

Cette fonction renvoie l'ensemble des murs « intérieurs » du labyrinthe : les murs à l'est des cellules de la dernière colonne et ceux au sud de la dernière ligne ne figurent pas dans la liste.

Pour faciliter la correction du code l'aspect « aléatoire » est limité et la fonction murs_aleatoires renvoie toujours le même mélange pour des dimensions données.

Remarque

Toutes les classes et fonctions citées plus haut :

  • Cellule,
  • base_labyrinthe,
  • dessin_console,
  • murs_aleatoires

sont déjà chargées en mémoire. Il est inutile de les retaper.

Compléter la fonction labyrinthe prenant en argument deux entiers strictement positifs hauteur et largeur et renvoyant le labyrinthe obtenu grâce à l'algorithme de Kruskal.

Exemple
>>> HAUTEUR, LARGEUR = 4, 10
>>> lab = labyrinthe(HAUTEUR, LARGEUR)
>>> print(dessin_console(lab))
 ___________________
|  _____|  ___|  __ |
| |  ___|  ____  _| |
|   |  ____ | |___|_|
|_|_____|___________|
###(Dés-)Active le code après la ligne # Tests (insensible à la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Alt+: ; Ctrl pour inverser les colonnes)
Entrer ou sortir du mode "plein écran"
(Esc)
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activé, le texte copié dans le terminal est joint sur une seule ligne avant d'être copié dans le presse-papier
Évaluations restantes : 10/10
.128013sH3_8èufvIy |7nGaêS1me(P4C2V:Kjtwi]D[hE*)6Oo;bcdUg/T0làqAp!.rFL-,=+Nzk95Rxé050W0w0G0r0I0$0b0m0V0$0r0b0b0=010G0I0*010406050b0h0v0v0r0-0l040t0S0$0h1f0S0p0m020r0v0*0T0m0|0w1p0-0(0h0w0b050Z1m1o1q1s1k0*041Q1X051!0Z1!1$1X1k0W0I0j17191b1d0M0I0Y0M0$1@0M0G1i05120U0$0w1/1a1c011?1^1`1^0G20221~0G0U0S0W1s1 0-1Y0G0M171v0b0*0r0p1d0B01241;010i140w0p1D0w1~2s2u2z262C222F0v2H040a0m0y0-0S0*0S0b0I1y1A102q0-0-0w0V2$1Q2J0p1Y0Z2o2=0G2m2l2n0W2L1d1`0p2E2Z1~1,1.18252 0I310p2i1-1~0*2+1Y2:2=3j1l2t1A372A3c0-1p0$1i0m0u2/3n1j3m2K3p263r3t3v0B3y2u3A2:2~013F0r3u040m0d3J2;1k3M3D1d3P3R0m0z3V3L3n3N3#3v0{3)3X3+3Z3O0S3s3Q3v0Q3:3B3o1:3E3^3G3S0o3}3Y403!423`3S0f463=483@3_3$0`4e3C4g3-040u0#4l3 384h430u3x1R3z3;4m4u4o0u3I4z3K4B4t3q4a3R0u3U4H3W3~3,4M1i0u3(4Q3*4C4L4i4V3/4Y4J4T4$4p3|4)4S3?4E454/474D4U4p4d4@4f4_4,0u4k4}4!414,0B4r534K55430B4y3j4*4;4`0B4G5f4:4n5i4P5l4^4#5c4X5q4~5s4b0B4(5v5449564.5B5a5D5c4?5G4+5c4|5L5h56525P5n4,0d585T4 430d5e4A5m5Z4b0d5k5%5r5b5*5p5-5w5/3R0d5u5=5C4v5*5A5{5H5}5^5F605M5*5K655Q5!5O695U5!5S6d5)3R0z5X6h5x6j5$4I5(6n1i0z5,6q5.5I4b0z5;6w5?6y6j5`6C5|4o0z5 6H616J646M666j686Q6a6z6c6U6e6z6g6Y6i1i0{6l6$6s040{6p4R6x626(6v6:6D6=6-6B6^6I4`0{6G6}6N6 6L726R6(6P766V3R0{6T7a6Z7c6X7f6%6-6#7j6,0Q6*7n5@1i0Q6/4Z734,0Q6@7w77040Q6|7B7b7t717G7g7t757K7k0Q797O7o7e7S7s7D7i7V6E7t7m7Z6`0o7q7%4o0o7v5g7L040o7A7/7k0o7F7@6,0o7J7{7W0o7N7 7!7;7R837(7U877,7Y8a4`0o7$8d4,0f7*8h430f7.6r7W0f7?8p840f7`8t6`0f7~8x4o0f828B4`0f868F8i898J8m8c8M4b0f8g8P3R0`8k8T1i0`8o6;4o0`8s8#4`0`8w8)4,0`8A8-430`8E8;4b0`8I8^8U8L8|8Y8O8 040`7$1Z3h1Q352^0W2|3N0V2i2R0 1-1Y3g0w3i3z3)059e109m5|0_0p1i0I1E3^0G9o6;0H3v9B6_0p9v040-2u0W0S0v3:06870_1i3D9F5|9D3S9V6N0V1i0A0w0$1w229Z3N1h040D3:0m9=0m8x9S04100i9,3?9X9@4Y8x0i0v1i0e0e3a2#a69}4g9.0xab4u0U9.0b9(9|a16;9.0;3)9@8#1i0^1z0waf2A9.0P9:4)9?aDar6_ah1iaj0$al3l6;0S1i0,ax3E1i1O9A4YaF5|aO040=aq9^9#040!0-1N9;aE9=8xaH04aJaL9naNaPaR3!aI0h0Wa$a_a!b06_0_a(a*a,aCa.aX61a;a?a{01aZaQam9Gatavb3aY1ia#aW8Bbl319PaD9^1i9{bf9 bfa3a50e0b2_aabj5|adbfbdakbfazbn61aZ0:020Y0G0TbR3,0UaI2_bP1iaB5fbabb3N9_0Ia@3Kb-3?bNaKbfbhbf9IaUbZ3?0S9X9Lb 4gb^b;2;8xb{bJ6Na}a cb9-b)a-b,a/6;9_2+0G0h0-0pc44u0b2x04010e0n01ciaEbx049(b:cs2Ac6b`a`cf4;aTbGb(9/cBb,cDcncpcrbr6;cu1i2yczcS9?cDcFc79Y6;cJcM4gcaaMbka=a~cQb*4Acjc)cl1icVcqcH26c!cwa6cAb9a.c*15awc:4u9.c{4Ic}ckb4d011cWd31dd52y0md85f06bwc 9`0wc,8xbBde2AbD04a62+3gbIc?bK1iaedE26c/dM61bQcY6_bTbVbXdp3Ob#a=b%dQ1ddgc(dk9tdmcod2dW5|dSa^dXcLdT3NdGa6bG0-dLd_dN040x0P9P9RbydAbA9Ed*3O0i1i0U1a0w0e190U0l0-3a2oddd|3?bLee9I0M0r1x0wcpcQapd?cc04190-0YeB0-cQaAcBbseH0r0Ud#aZbq3jb?ac1i0L0JePdy0i3^d#9I0IeU9X3ae+d%9K0peKcQdPet4n1ieyeAeCeeazdh3WcTaseH1@bueF3NeVd#9.0Lb|9$9(9*ese3dUdOfg04e-fac01i0Oe+1ieIeKf0eXc91i0?fv040FeNd#9_e)eMfre|fFe.9wcXfA8#e=2ue^f1fnewfw1qfyfLe{df1i0Pe$d9cCf6emcK04bif(3q1i0r0*0*2Ecef@26evf a|f70Yf9g201dVb+c~dl9Jdnd=fSc@f:4)9QcDbzeedDg70pegdz1b3a0e9e0p0b1vfk3K8xg1fl3,f!eTfX04eOf-eQe~0GeLeDfEfxgPfM4ufcgU3qd%2Oe_fogig7azeEgg6IgZ2Eg#fZeRgHg(e!bf0v0I1i7*gC1i0Je7gLf/f81OeUbpfdg@eedrbfaj1i09fRgE3?d5dth504fDgXd4cvcx0edu3zeYgVfth7e5g$f#gTg+bS1i0:d#g_4VfHhn1daZhmhC3NdrhrcQf,gad.61fJe*hK3O9wfPfphfb=8BfUe@gAc8anfYgpe}ezgOfzhgeZgJf31jf5ghh3hkeWhtg}04ffh9hpc%gIhTi3b1hNic6_feb|d%e0g/h;g;cQi6imfqg?040Jiph_4D1ifGiah0hO3?hXf%if6Iiyh$e:hZ0ph+fWise`iwf^eReJhBiRg0f*ibdibaeQ2a311Peec=iWg3f`f|0pf~i,g8h:i=drhsgBb1f?i=9I0F0SiKiPg$i0gI0PiBc|gbiHgs2!h(2;hu2AgWiC4ghah92Rhehbhpf;i}i{c@j0j2i=gDjtjbi%h4j6hkieh)cZjqjmhdje9s61jlhUjg26cmgejLjQg310gtjL9Qe9dzdB9Cedgpgr0vcp0b0e3Q0w0r0Gj12+i)j3g:gNiVjzfm04g*iGeGgSh^j~cgk0fE0Y9K3ah-jMfbh6eehH4peNh|dwjaeGj,0-j_k2kfb2hZfeiZf4knb.1ifKfEirksc0e/jUh*d0fVkdi4iQk6cN04j|k5jffB04hFhZki7vi4gKjPdxgckCiLiIhZc1fQe;kKh,ili~f!iUkTc-d`kWhGg`kjj6kldjjVh!04kpkrkPc;d{k@04i.f}e_kOh.c@kEl9f)k8k+fOgIk1jG6_draUi`lie4j7d-f.c@l7jrfolei:lgfolklxj lrkUf6izislNk{5|dr1m0Wlwkeeuf*j8i!hVkA04k*jjixfpiJkIfTk;iOjxi@lliSkSiFlsbok}kYk k!h/h{lAeQlDi*lbl_aSldf{lfgI0xlhlZfNlKmilmlSl49Ik4l|lOk|kXl,2AkZgQhZdr3rlXeNl$kyl(iDkBhYmvmblQkFc;kHk:9JkLk?mag3mqhkmumN4umxl1m5f6m7g7i+mUl5lGi;m,admhgMh?j}msl~mYl}61m#lRfEmMm:1imn8xlubGlYk#mEh}kzkQe?9M9Om8f=foaj0wm/lLk7m=f6ka13g6l@gJe%c@ne9NlEg:0b0M0h0i0i9+mffom)nunakmmG4gjSd;l:lCj-e8glebgnj)i~gremeoeq0MkMm3npc@l{mymKmVhAk`k#l2ncfNg%mZjhkgn:l5eiajeleSn%0permTnnkQn.lqgRn=mrmlayf*nwjbnKm|kti2omkQl7j/22j=j@jCj`imobm lomWjDgjk(d/040H1?nHn iMfwg.nIg:olo9h`nal4aZ0+oom_m}k g|m3n^daf60Im2ign3n0o,e4n4f63^0I2E122.k-n~n|mboRog26m+oSl-2Y0*e_nMh~oGcGloo@o_j=0I1zi1oYlTjNhplvc`lAoFeG1,i1k~g{pqn_l-0Wn1oZonpvl0k%py2A9_9(ajppf-papsmkoVo}op4gm~j9c}eQpApum0pwpNpHmb0I7ApRkuoL9w7vp,jFpCkQptp%nOl-0Fp+kVpkmoiyp:kVp=plgF9`pBnbo)gcpcp.ingIivm,e,o:j iufo0Fqjk7kxp1hLm9p4iSauntpThv04oXodg=nuqgqup)7Ai4qlg:p|hSnAimqwn*o-cRp_lBpbc,q004peo6pgpio|a!p n5pnn7pMpGpXf/eSiolJqol!itqFqrl5qnqNnhjsqGg3b~q(q*cla(0.3QpLqUprl)pKqRe4o(l3qYn{n2i5q@hSq{eQq~iaqOlclWp!n b51ir9dcbvdjeQ3c0h0jfiekqQrxo~n;qDrmrqo*q^h`qKimrsisqqkVr1q|9IrLrcp(i-0p0Vo^9HrKbmr5qCq?g:p*rpqmqIm3rZi|for(q/qVhWmIofqYpQc9mPiLiNrgj n,jboznLril3cDl+rNq}l/mQe?l?rmsfk3oekkpxq:qbqXi$q=qflJr`qLq m*qtr$btkdp,0=r6c@2ur-2E310es1nusjrjqajAsDisrRljsGrWsIi=p3sL04sXqyn}p-sn9IrGrI9)r:qx3WnNl4nQdooBs%4Agk6;0V0u1i030m0!r45YiS0c0)0X0!0N0X0|n/s_1i0/0)0|0qtntpr=p#047Ji4o=6_kZ8Wq;rPp?las^s?mbn$epo6n)o8s:tjtltxtqtNg3tttvtXoDthjRf_1b0w0-aVn jymFqYjXjdgv1zgyoKnusuq6rlr2i?nvh1k|sPd#i_lY87hia6ucudueue4shPcv0naDcy9=ucuk0na60mupuhhhujum0mcyuruq0eunud0nuujkujaEuBuAuJusuGctuwuquKufuRuouO2Au8uWiXu35l0Z9q9l96u)0Z991Q0G9bu.2`2?2h2j2^eS222=991Wq|2+0v0e0i0r0_ek0M0d1i1I1K1M1O0mh|1Z3A1X0/003Q0Yo@2o2Q0m2(0Ea+0b0_3Q0maU0m0h1Avlvn0Mvpf|3s1112o6vq23gwe00h0I2+vzvB0-0UvR9erHe?0G0mg_0p9xvw250Sr-0~0m0%0mnr0*n)0m2Yi:0~0-0~bi1*1#040K2u16gy1Ae)r,2$312QvK3D0Ivc0;0m1zv@1qvXt.0m22161q0sgO160W0hv:9Kv=230Ww2wm003^0WvR2(22j-v@j10W160V2W0I1b2u0G0b0,0mw1gxwm0r0mrIkqph1A3g2X2Z0~230Ir-wf22wi0-wkw323v32#vqwAvAwg0-wE233Q0~ouvQ0wv}vh04vj0~12f|2q1E1`1Mw,vLwBvCepvo23vy190m0i0h2!whjX0mqQwT0m0/vM0Mj10}v@2W2Y0bv-w.0IxkbGv+v50-wYxyavxk0Veyvc17fi0hw;9e1ox22cep0U1xxWrJ0:r-0m0p00vy2t16w;0*1w16dA2C0V0r0Vxp1AgOvHwsvM9Nx}0w0}2#v-0Dv.17xY1Nxsxuw%wg2%j1v!2tw?0ScpvQwB2Eaj0v21wyvdy49)x$1Ox8u~0Rw(yv2*13ys2W0V0~10xSh?v0o_vx1A1x14wPwRw=vx0}1JycvLx gx1JyC0bwf9p9f3N281_1{1}r$ij119ou%9f3S0rrI0V2U0l2o1zwf1pwPx!2c23vO2-cp23x@x_1a0mezxH0Snrx)xk0@0t0kyJv vjx3x5vRvygw2_nsv!wzwXy4v!ydt-r-y4zq2C2%23j?0hj0wI0S0UgOv%xSwnv#0s2Qx{o4tQer162Ycpy.vq9xyzw%ws1z0pw,wTvgu~9%zh2qo6kbo6xpbGwm0IxjzrxXxFxkxrnrkcAivk0$x4j?x69@u(y`1{2a1|2Inx9Lnzr0nj0wnltTeQAks q|g99nz39r0m1MxNvyxMxs0I0}xjv/y^9r4yu(f=1H11x6xSzNgOAcg5w_yPAPyl0yzaxE3oxEwPvQwZ0$00n)zlzqzkrJxfvpAIxpv!0Y0~0p0g2+9Kz^0v0~19h,z=aja~0S0:zDAqj^v@x~w!kbyA21u`yI0m0Cj@xT05wZ0M2+0i1=2c0*0b0D0Zu,v+wT0*A^1z0,3^0Y0Z0i0-0Z0d0Z1`vV1U0Zny0v0,1|0v0$03B.0,nklX9`v+1npf2$wgnFxMrJ1Q0rni1%3Au,11131504.