Aller au contenu

Plus longues sous-suites communes

Introduction à la programmation dynamique⚓︎

La programmation dynamique est une méthode algorithmique pour résoudre des problèmes d'optimisation. Le concept a été introduit au début des années 1950 par Richard Bellman.

Comme dans la méthode diviser pour régner, la programmation dynamique consiste à résoudre un problème en le décomposant en sous-problèmes. cependant, ici, ils ne sont pas forcément indépendants.

Ensuite, la programmation dynamique permet de résoudre les sous-problèmes, des plus petits aux plus grands en stockant les résultats intermédiaires (technique de mémoisation).

Voici un exemple avec la mesure de proximité de deux chaînes de caractères.⚓︎

Considérons les deux « textes » "LAPIN" et "CAPRIN".

À quel point sont-ils proches ?

Pour répondre à cette question, on peut se demander quelle est la plus longue sous-suite commune à ces deux textes.

Définition

On appelle sous-suite d'une chaîne de caractères, une chaîne produite en enlevant zéro, un ou plusieurs caractères.

Par exemple, "AN" est une sous-suite de "LAPIN".

"AN' est aussi une sous-suite commune à "LAPIN" et "CAPRIN".

Dans certains cas, il peut y avoir plusieurs sous-suites communes de longueurs identiques. Par exemple les chaînes "abc" et "bac" admettent deux sous-suites communes de longueur 2 : "ac" et "bc".

On va donc plutôt calculer la longueur de la plus longue sous-suite commune aux deux textes.

La comparaison de "LAPIN" et "CAPRIN" donne ceci (sur fond vert les caractères "identiques", sur fond rouge les "différents") :

LAPIN

CAPRIN

La plus longue sous-suite commune est donc "APIN". Elle est de longueur 4.

Écrire la fonction lplssc (pour longueur plus longue sous-suite commune) qui prend en argument les deux textes à comparer (texte_a et texte_b) et renvoie la longueur de la plus longue sous-suite commune.

On propose deux versions de cette fonction : une version récursive utilisant la mémoïsation et une itérative.

Ces deux méthodes permettent deux approches de la programmation dynamique : une qui construit la solution en partant des problèmes simples et en les combinant (bottom up), et une autre qui part du problème initial, découpé en sous problèmes, eux mêmes découpés par des les appels récursifs, jusqu'au cas de base (c'est la technique top down).

Exemples
1
2
3
4
5
6
>>> lplssc("LAPIN", "CAPRIN")
4
>>> lplssc("abcd", "abcde")
4
>>> lplssc("aBaBaBaB", "aaa")
3
Aide

Une approche consiste à déterminer les longueurs des plus longues sous-suites communes de toutes les versions de chaque texte : la version à 0 caractère, la version à 1 caractère, etc. Il y a (1 + len(texte_a)) × (1 + len(texte_b)) cas à envisager.

En prenant encore une fois texte_a = "LAPIN" et texte_b = "CAPRIN", les différents cas envisagés apparaissent dans le tableau ci-dessous. On trouve dans chaque case la longueur de la plus longue sous-suite commune à chaque texte s'il s'arrêtait au caractère indiqué en début de ligne ou de colonne.

Ainsi, le 1 au bout de la double flèche est la longueur de la plus longue sous-suite commune aux textes "LA" et "CAPRI".

Tableau de longueurs

On constate que :

  • la première colonne et la première ligne du tableau ne contiennent que des 0. C'est en effet la longueur de la plus longue sous-suite commune dans le cas où l'un des textes est vide ;

  • si les derniers caractères considérés sont identiques, ce caractère commun fait partie de la sous-suite commune. On peut le supprimer et ajouter 1 au résultat de la case au dessus à gauche (flèche en diagonale);

  • si les derniers caractères considérés diffèrent, l'un des deux caractères (ou les deux) ne fait pas partie de la sous-suite commune. On compare les valeurs des cases de gauche et du dessus (flèches horizontale et verticale).

Version récursive

Cette fonction fait appel à la fonction récursive lplssc_rec qui prend en paramètres le nombre de caractères de chaque texte à comparer taille_a et taille_b. Cette fonction renvoie la longueur de la plus longue sous-suite commune aux taille_a premiers caractères de texte_a et aux taille_b premiers caractères de texte_b.

Par exemple, avec texte_a = "LAPIN" et texte_b = "CAPRIN", l'appel lplssc_rec(2, 5) renvoie la longueur de la plus longue sous-suite commune à "LA" et "CAPRI".

On gardera trace des résultats intermédiaires dans un dictionnaire longueurs qui, à chaque couple (taille_a, taille_b), associe la longueur de la plus longue sous-suite commune.

La fonction étant récursive, on débutera par l'appel prenant en compte tous les caractères de chaque texte.

###(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 : 5/5

.128013oèPf8gïbr1a}3tv=u{àn9xsc)7qR/p0Od?; lk5:jQ+,y2éChw6e[(ES]_im.4D-050H0!0o0l0+0L0x0K0y0L0l0x0x0q010o0+0E010406050x0r0,0,0l0j0T040(0b0L0r140b0u0K020l0,0E0J0K0C0!1e0j0B0r0!0x050D1b1d1f1h190E04051M1F1P0D1M190H0+0p0|0~10120~0u0g0r0l0g0!0:0E0T0o0X1o0K0X0+0g0X0L1^0X0o17050@0i0L0!1Y0 11011@1_1{1_0o21231 0o0j1N1:0|1k0x0E0l0u120U01251!010e0_0!0u1s0!1 2n2p2u272x232A0,2C040a0K0d0j0b0E0b0x0+1n1p0=2l0j0j0!0y2X1F2E0u1N0D1:2-2h2j2i200H2G1#0+0u2z2U1 1V1X0}262`2|0u0b301 0E2$1N2+2-3d1a2o1p322v360j1e0L1 0l1?2$0e12030*0*0y370!1{350b0:0k3E170K0k1F0l3e3h183g2F3j273l3n3p3r0!3t013v3x3z3B2}3E0:2s040K0U3K3M2p3O2+2_013T0l3o1N3q0X3s3u3w3y0=3%363)0n3H0n3/2*3N193?3R123_3{053}3 3Z413$2{3(3F0.3H0.4a1G4c3P3i1Z3S0b3m3`3V3~3X403#434p453F0N3H0N4v3d4d3h3@4h4F4l3!423A4L3D3F0Z3H0Z4R4x4e4A4g4C3U3|3W3Y4Z4o3C3)0A3H0A4,3;4T3Q4/3^4;4E4?4G4^4n4K4{3F0f3H0f502,524z33554D4i4k4H4m4J4#5d0:0v3H0v5i3=4U4f5n4=4j4@4I4!444%3E0F170k0F5A5k4V565p5H5s5J4$3)0k0k5O3J0D3L4b514y5T5o4X5r4_5c4q3E3+0k3.5)3:5j5-5D4W584Y5b5u5@0k4704675R5 54615G595I4`664s694u5|5+5~4.5m6e5q5a5t5K5!4O694Q6n4w3;1Q3b1F302:0H2j2^5D4!2 1W1N3a0!3c3N6o1N4!6T2F0+0H123w2+5!3V6!6$6v5Z3F5$0K2K0!6,5Y5v5$2-5*6q2v0M170=0e6V6c5m0Y3H736}3S0e170L0E0`0x0y785C5416040$7i536r170o0!0w7s0*0l7o5l2v7l0S6V0K743k7r7t7v0i7y3@7l0z0O6V196C2,5-6+016%3h3)3+5G7V646w3F2s6;2B6@6i4M3*1 5|0K7?7E79126 04717L5D763,7~6d7b047d7f0y0*2$7h7S6Y7z277l7n8c7F3S7r0^0L237w825m7B7D8j4g8l0_8o7K8i7_017N7P8c7R3f3?7$0*6(3F687#6#7W6-5v477+2L7-5?7/8N7=7@8#8u017{0+728c7^7j7q040@8x0!8p8,8%0b170q0q8t8B0,0+175Q8^8B0b804C8~8.7G8:8m8y997p2v8`048|9f8e1290928q7A178E4S7L8J8L0:6k8O8W657/4s8U6?8Q6^5@9z8!8#9M8-9g277{2$0o0r0j0u9l3@9o04939u8A4U9w7Y4N6*8P7%6.0:4O9F9B7(9:7;3L9N7?8%8)8+3d9O9m8C178h8H9a8k9c8=8@a69P128s94a78va98n8?8zaca27N9X5D9617360oaq54as042{aw8/0L1o1(0!9U1E9%ada3049t4xaJ1p9)2p3)4)4?8J9I7/4)9=9H7.5LaU3/9{9M9}178*aB9b7s7u8?7xaP7M170#9qa88;akab3Na13@9i0:a/279Z5(ana_040)b6129i9kagaK0u7Ha=0*am6U8B7la{a^608wa bo3;b2ar17b5bia2b8a|ae170)aN5,a^aR0u4|9,9?9/4}a!9.5v4}6{3,a*9{8%bk85aE1CaHbGaL0#a5bpah3^bv8oa@ba5Dafa0b$b?alb,7NbdbDb38{be01bFc3bA040Rc6b%8610888ac0a4b,b%a~b@c6b4c6c8b_7k177Cc96db~bncpbBcr9169cj040z7Q9v9-8K9*0:5faVcLaX5L5fbU8R5@cPa)b!9|8B7{3A0x0!cGbK5~bMcL9x5xcQbR5v5xcVcS3)c;cZc!8$8Bceb)aG0jaIct8ra`b/6Dd0czb^b:aKb{b1b}aj9ebtcucHc2b|95c5cx6r0i171e0wcGd9c-babN5!5Nc=a#8X5L5P2t6=c?66dEc}c~9Ndicf7g892%dycldccB04bCdpb;csdeaocvcdczbx7Tbq170zcwd%bj7c7ecgdV8bd69r7mdYdja?cGd@dhdbe3cAds9hcCebb7cEb9d*bbcI8FcK6,9x5#bQdG9CdI6:dLer9@epbYdQc b;apelc.encN5`eqbV667*eveK7/eIezb#c$179S9U9WeeaiaD1%b*d4cGb.e2cne4dld704e6bydie+ead 8fd=doaOdBc/eH8N3qaWa$5!8TeNcWeP8Z3L8GeidC6/9zf1cRf3fedK7,ew9/0k9K9`7@dSd2b+eY01bgc67l0s0mcJeF8Qeo6y9Afm6_9;f6c`6/fG9Lbz549R0?eWd-85d{dUcie-e0dz8d4Vdu852zdXf!a}7Ie,e^bHcHe:2,fQdt7cf+f-f=f$e=f/e@eib`d=ek9$3f0D6X6E6S6G6P1F0o6Jgf2?2.0l22gc0D6H1Lf%5D2$0,0*0e0l0M8?0X681x1z1B1D0Kc,2-1T1O040/2p0{0~0K0e1o2(0+1=3a2{0y153`241=3y1d2z0y242o0j0|0j0V0!g-230K1VgT1o2A0+2$7E6Xe!aFfu6X0K2{2W0+g!2L0u0o0K0p6!241B0+0K0Eg;2L2d0j3q2Z051y040,0V0,0b0hc)0j1Fhr0-060G1p1$g*0K2z1b2W24230{0l0Ehj0`0Kg/0yaH8*0{2z0Kc)g@1y2p0H2phbgEakhI0xhbgPh0e$h$0KgP7e0rgOd2h!0bh{0:hK7s2l1d0r2|h!hh0L00g$1o2V0H0c2$060oh 7sgOgF23hmgF2Z0y0X0lgE0Ka;i30Og~3zfW87d}0$2J0$ixa?d?h^2ziHg10i0zekh30I1Q3O1M0W0bg(h^3q0xh 0x0:gR0ug_1p1DhbhUhW0p0!0Sh40Lh.hb0i1=2Z0H0V0i1mg;hi1f0Ki60|0 h@0i0 0!hC0W00i.h4gYiLj80{h h^00j70=0{0=0r0wiwf/0{i73yha0+2zhb0l0rhV3i1f0l2(igjd0KgM0u0{hH0y0 i@1=2$0u0p0bjCg@g|2%7sh9hb054!3@1$1(1*1,1.1?1|2b1}2Dd(cE9#6Ug9iB0-iUgqhEhc0V0j8*j#hJ0rhL0Kivg?jThO0K0V0o0Viwhn2Wkmjn360u0-2Ph g-g*gP1=h#0=1e0u2Z2Vi!1Ykmj,iBiH9da?i@e?iP1F6X060ujgh/j40{3a0Vc)ha24h)jQjkg^2Xg{g}kK0=b(e#d3aI6Xk21SiV1ihh0ykWh:24khi@0_gQjFhb2h0^7skx0?i3g%g,0^i$1p8EgJ0r0L3O1{04kGhNh$9VjCd4j8hnjL2$jRid6!k7k#h~hah40=jBgE0xjV1p2o1024jFjvjTly0ojMkZhU0VlJ0ohYh:ib1p0l0Pik24k:l254j/1)1+1-0Tj@2a1|1~gr54d)6Dk0k;0KjFhTk#lm0@hb0J1Flp19lplrgFlUjKlWlAj$0e0ejMhalNkj9T1VhMiqaGlTj9k!gY0xlFg,jo0Vks0y0Vkuk57ejKk(gNk+0+i,k.mvm61b0Lm9jkh`0{0ghnkEk`md1Flmk|0Q1Ci_ivi$2WjkkhhIjY0+0x1*0Vi@gP0pg!9Ui`h41dl!h7j)jDh!ij0y0Mg:g@mPg?k,gU0umTiAk;h=k@kSk1k3gK0%2Yg;0ulvh^jC0rmrjXjZj#n0n2g-kfl)hcjClH0H002{mC2$g-k)imj$mS0^g}jnkyg?hgmslag@0V0P0thig/k$7sk`gJgo0?8m0x04.

###(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 : 5/5

.128013oèPf8gïbr1a}3tv=u{àn9xsc)7qR/p0Od?; lk5:jQ+,y2éChw6e[(ES]_im.4D-050H0!0o0l0+0L0x0K0y0L0l0x0x0q010o0+0E010406050x0r0,0,0l0j0T040(0b0L0r140b0u0K020l0,0E0J0K0C0!1e0j0B0r0!0x050D1b1d1f1h190E04051M1F1P0D1M190H0+0p0|0~10120~0u0g0r0l0g0!0:0E0T0o0X1o0K0X0+0g0X0L1^0X0o17050@0i0L0!1Y0 11011@1_1{1_0o21231 0o0j1N1:0|1k0x0E0l0u120U01251!010e0_0!0u1s0!1 2n2p2u272x232A0,2C040a0K0d0j0b0E0b0x0+1n1p0=2l0j0j0!0y2X1F2E0u1N0D1:2-2h2j2i200H2G1#0+0u2z2U1 1V1X0}262`2|0u0b301 0E2$1N2+2-3d1a2o1p322v360j1e0L1 0l1?2$0e12030*0*0y370!1{350b0:0U0:0k170K0k1F0l3e3h183g2F3j273l3n3p3r0!3t013v3x3z3B2}3E3E3I0U3L3N2p3P2+2_013U0l3o1N3q0X3s3u3w3y0=3(363*0n3I0n3.2*3O193=3S123^3`053|3~3!403%2{3)3F0.3I0.491G4b3Q3i1Z3T0b3m3_3W3}3Y3 3$424o443F0N3I0N4u3d4c3h3?4g4E4k3#413A4K3D3F0Z3I0Z4Q4w4d4z4f4B3V3{3X3Z4Y4n3C3*0A3I0A4+3:4S3R4.3@4:4D4=4F4@4m4J4`3F0f3I0f4 2,514y33544C4h4j4G4l4I4!5c0:0v3I0v5h3;4T4e5m4;4i4?4H4Z434$3G0F170k0F5z5j4U555o5G5r5I4#3*0k3H045!5Q4x5S5n4W5q4^5b4p3G2s5$3-0D3M4a505)5C4V574X5a5t5:0k465$485^3/5i5|535~5F585H4_634r5$4t685`6a4-5l6d5p595s5J5Z4N5$4P6m4v3:1Q3b1F302:0H2j2^5C4Z2 1W1N3a0!3c3O6n1N4Z6S2F0+0H123w2+5Z3W6Z6#6u5Y3F3H0K2K0!6+5X5u5#496p2v0M170=0e6U6b5l0Y3I716{3T0e170L0E0`0x0y765B5316040$7g526q170o0!0w7q0*0l7m5k2v7j0S6U0K723k7p7r7t0i7w3?7j0z0O6U196B2,5)6*016$3h3*5=5F7T616v3F2s6:2B6?6h4L3+2-3M0K7;7C77126}046 7J5C74047C7Q6X7x787a7c100y0*2$7f817D277j7l8c7@3@7p0^0L237u7|7i177A817?7h7o040@0_8n7I8h8v7y177M7O7J7!0*6%3F657Z6!7U6,5u467)2L7+5/7-8N687=8#8u7n6|170+708t8d4f8k8z0!8o8-8i0b170q0q7B8.010,0+175P8@8D270b7~4B8}8i0u8:8m8=8B3d8%83128_048{9a951290928p5l7j7N817P3f3=8J8L0:6j8O8W627-4r8U6=8Q6@5:9E8!8$9R8~7_2$0o0r0j0u9o8(279r04934R8I8P7V2p3*6x9F9M7,5K4N9K9G7$0:9:9Q9S8i7_8+9!9j018f9t7E8x8l8n7v8C9#127za34U9d8Aa78e8Fah5C9717360oao53aq042{au8w0L1o1(0!9X1Eada49v8HaH0K9B7W4%6)9,8R5:4(9_9=8X5K4(7/7 9R8$9T8*8,9h8~9c8x7G8=ac9z9pa5170#al8/a98;8?a+8^170:az2v9%3KaL5C7j0)b3968`8|94ae8ja.7s9fa`a@04a_b76cajbkbfa49lb2bt3?b5blb99w9*aLaN9.3F4|4=8J9N7-4|aV7#6-0:bI3.a$bU9iai04aB1%1CaFbAa^8ga=bga-8y9ea~6T8iagbx5}br0*9gb:a?7Lbab?av8`bb9q915$c2019l0Rc6a-7b7d888ab%7kblb,aaa:c6bvc6bzbp9u8rcab^b`3:bWapb1coc4b6b*aIan9x9+6+9C5ebJaRbL5K5ebOaS7-cKbTbV7;a(043A0x0!cgbC4wbEaR9C5wcL9`bQ5wcQcN3*c,cUcV8#a,7aaCb#0jaGcD7Kb(cib^a;b{bgb=a a?cja}cv7Rb;8Fb~dabg9lbedja40u0i171e0wcgb)c(d1bF0u5Z5Mc-aW9H5K5O2t6;c.6^dBc^c_9 db85cd892%dud4a|b.d6cw8~cnb 5lcpd1b8csd$a8b-akcq8E040z8sdnbXcc87dS8bd)8qchd:3Td5cgd@3OcxbqdWd/d^cy04bweb53d(d7cEd=aKdxc*aO3G6_3qbK9?5Z6/dIdD9{5!1 9~dNe7crekcGc)cIeo0k7YercMet6.7(ewbP6^7YeBc`a0179V9X9Zd,e2bYc}aEc cg0#dv6C9be3e1afd+ef8wd.bsd~eE0zdidweiaMenbG3G8NeMdJ638TeRcRdF8Z3M9yf1dy5Z9Ef7exbQ0k9Jfbc=6.9P7:7=c{e(b!e*d0e6d!c1e$e?040s0melfhf3dz6.9:fleS639^fqeO3G9}fucWeX04eZ9YctbY867ed|dUe=3@dqbY2zf,e|d-a/b/e/b|8Fe5dZ9bf/2Jf=f1b@bi7Hcg0z0zfJ6C0D6W6D6R6F6O1F0o6Igi2?2.0l22gf0D6G1L823?2$0,0*0e0l0M8=0X651x1z1B1D0Kc%gb1T1O040/2p0{0~0K0e1o2(0+1=3a2{0y153_241=3y1d2z0y242o0j0|0j0V0!g:230K1VgW1o2A0+2$7C6WbZaDb$gc3z7 2{2W0+g%2L0u0o0K0p6Z241B0+0K0Eg@2L2d0j3q2Z051y040,0V0,0b0hc!0j1Fhv0-060G1p1$g-0K2z1b2W24230{0l0Ehn0`0Kg=0yaF8+0{2z0Kc!g`1y2p0H2phfgH9ehM0xhfgSh3c~h*0KgS7c0rgRe)h(0bh 0:hO7q2l1d0r2|h(hl0L00g)1o2V0H0c2$060oi37qgRgI23hqgI2Z0y0X0lgH0K7qbjgJh1h7d`f*8a0$2J0$iB7t0ld?h|2ziLf^0ig81F6W0K0I1Q3P1M0W0bg+h|3q0xi30x0:gU0ug|1p1DhfhYh!0p0!0SaM0Lh=hf0i1=2Z0H0V0i1mg@hm1f0Kia0|0 h{0i0 0!hG0W00i@aMg#iQje0{i3h|00jd0=0{0=0r0wiAa/0{ib3yhe0+2zhf0l0rhZ3i1f0l2(ikjj0KgP0u0{hL0y0 i}1=2$0u0p0bjIg`g 2%7qhdhf054Z3?1$1(1*1,1.1?1|2b1}2Da?9%9)6Th60=040-i!gthIhg0V0j8+j+hN0rhP0Kizg_jZhS0K0V0o0ViAhr2Wktjt360u0-2Pi3g:g-gS1=h)0=1e0u2Z2Vi*1Yktj=h7iLck7ui}e`b_g9k66R060ujmh?ja0{3a0Vc!he24h-jWjqg{2Xg~h0kRk7h_fziWh7k91Si#1ihl0yk(h@24koi}0_gTjLhf2h0^7qkE0?i7g*g/0^i,1p9wgM0r0L3P1{04kNhRh*9YjIc jehrjR2$jXih6Zkek-i2hef2jJ0+gH0xj#1p2o1024jLjBjZlF0ojSk+hY0V0=heh$h@if1p0l0Pio24k{l953j^1)1+1-0Tj}2a1|1~gu5CehgbiXjLhXk-lt0@hf0J1Flw19lwlygIl#jQl%lHj,0e0ejShelUkq9W1VhQiuaEl!jfk,g#0xlMg/ju0Vkz0y0VkBkc7cjQk:gQk?0+i=k_mAmb1b0Lmejqh~0{0ghrkLl1mi1Fltl30Q1Ci izi,2WjqkohMj(0+0x1*0Vi}gS0pg%9Xj0aM1dl+hbj/jJh(in0y0Mg?g`mUg_k@gX0umYiEk|e)h56Wl1gM1M0%2Yg@0ulCh|jI0rmwj%j)j+n5n7g:kml:hgjIlO0H002{mH2$g:k;iqj,mX0^h0jtkFg_hkmxlhg`0V0P0thmg=k.7qnx3Pgr0?8l0x04.
Version itérative

Dans cette version itérative on détermine là encore les longueurs des plus longues sous-suites communes de toutes les versions de chaque texte.

On peut toutefois remarquer que les deux formules de récurrences (derniers caractères identiques ou différents) ne font intervenir que deux lignes à la fois. On peut donc compléter le tableau ligne par ligne en partant de la première et en ne gardant trace que de la dernière ligne complétée.

Une seule ligne est nécessaire

###(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 : 5/5

.128013oèPf8gbr1a3tv=uàn9xsc)7qR/p0Od; lk5:+,y2éChw6e[(S]_Liêm.4-050E0U0m0k0#0H0u0G0v0H0k0u0u0o010m0#0B010406050u0p0%0%0k0i0N040X0b0H0p0~0b0r0G020k0%0B0F0G0z0U180i0y0p0U0u050A1517191b130B04051G1z1J0A1G130E0#0n0?0^0`0|0^0r0g0p0k0g0U0*0B0N0m0R1i0G0R0#0g0R0H1/0R0m11050.0h0H0U1S0_0{011.1:1=1:0m1{1}1_0m0i1H1*0?1e0u0B0k0r0|0O011 1U010e0:0U0r1m0U1_2h2j2o212r1}2u0%2w040a0G0d0i0b0B0b0u0#1h1j0,2f0i0i0U0v2R1z2y0r1H0A1*2%2b2d2c1`0E2A1V0#0r2t2O1_1P1R0@202;2?0r0b2`1_0B2W1H2#2%37142i1j2|2p300i180H1_0k1-2W0e0|030Z0Z0v310U1=2 0b0*0l0*0j110G0j1z0k383b123a2z3d213f3h3j3l0U3n013p3r3t3v2@3y0*2m040G0O3F3H2j3J2#2:013O0k3i1H3k0R3m3o3q3s0,3Y303!0l3C0l3*2!3I133.3M0|3;3?053^3`3U3|3X2=3Z3z0)3C0)451A473K3c1T3N0b3g3=3Q3_3S3{3W3~4k403z0J3C0J4q37483b3/4c4A4g3V3}3u4G3x3z0T3C0T4M4s494v4b4x3P3@3R3T4U4j3w3!0x3C0x4%3,4O3L4*3:4,4z4.4B4:4i4F4?3z0f3C0f4{2$4}4u2}504y4d4f4C4h4E4W580*0s3C0s5d3-4P4a5i4-4e4/4D4V3 4Y3A0C110j0C5v5f4Q515k5C5n5E4X3!0j3B045W5v1K351z2`2*0E2d2/5y4V2_1Q1H340U363I463,054V5@2z0#0E0|3q2#5V3Q5 615o5F640G2E0U675T5q5X454)5h0I110,0e5_2$4t3/0S3C6p5}5g3e0e110H0B0;0u0v6v6r5y10040W6G6j3e110m0U0t6Q0Z0k6M5x4 6J0M6v0G6H4 0r6P6R6T0h6W4~5h6J0w0K6v134r5`3.6601623b3!3$5B6|565p4l3#2n6c6e4=76710A3G0G7g6$6N3N6A1i1Y0U0p0i1y6_2$7i6X5h0b110o6#6%6:110V6.6x210%0#115L7s3%7B2p6l040e4x7A7j4b110Z7U7v2p0b6t042=7Z6/3e0h110i2j1#7F3/6J6L7M7O3N7-042D7=6I117^397V3:6*6S0U6U7 6Y110w7*7G0|7x040L8e3/7I5J8a7C040w0Y6@7=730Z633z424.8v6f76426b2v7a578D1_7e3%7h7`0|7Q7S0i8k5y6)040.0:1}0Z6-7M7u7+217$117)8$8O3:7|7/1X0U8o2p7@8@7H7J5Y8`0|6Z8T6(7|7~7_848_957!7k8W6+888#83998 8c917w118j8-848m8}988(9h8q6?7M6^9f5~606}8w6 4m659A74699E8F2F8H754H0*4n2%7f7h9T8.8V6Q1n9j7#7y9Z216J7E9r8f019p7L378%9+8Q7T9n9g85047Y9@9s018*7(0r9$4b8:7:8?9*7?818~8/6A2taa979y9+9W9c89a7808qa29~9lao9p3Eal8b8q8s9w8u9G9C2j3!4J8AaA8C9O4J9K6d9BaH5GaE3*9T9U849=8S9|ah6P0/0H8Z6VaW3/9 8,9/9Va48=aea9au5hasa/046!a%8U93ada;8^a:ag4Q866Ta$b1am8da`4 8h9ma+9o8|atb6av6=8ta78v8x0*4!aF9M9Ibo788GaM7b9ObpaQaRbB8.7Q0#6ob95hai87akbh8p9)bM6O8WaZa#ao8h0*arbfa@axbd9^8h0o7zbHbQ6QbK9e5^967Daa9WbS9dbU11bWb*8{8na~9%110Y9v4Naz67bn4^bqbw8I9O4^aKbr5U3zc8bAbBck9:b29b9Yb 9tbOb/9^b?8Y88b5ct9}6Jb!3Icm5yb%bXb~b#9}bbao8V0H7m1w7p7rbPc004cs6`cuaYcwbLcD8.bVcH9qcT9tcC4|c59Bbn5ac99Hcg0*5aceca9N5Gc=cjclcE4 7Q3u0ua6c+016Jc34sblaAbn5sc?68c^5sc{c@5qdgd0d18N84aicpd89(b=cZa!cxbZb_04b)cJah7|180ta@82czaXco0Ba@cW6qdsdybTb|8gb`c)bgdMa8040Ya_dFcncO1XcQ7qdQdxbRc!cycXcAc1b8c4ddc69D5H9Fcf6g5Idldie38K9SbCdT7}cP7od/dWapdDcM6*dudcb1bmd 5We1c|bseqe5aN5V6h8LaS9^7Q2W0m7pa1egcNedcRd:cqab7}a}dvb0d#8Ub3dAeM6;c-5e6G0A5|5#5?5%5:1z0m5*e+2-2(0k1|e(0A5(1F6w3/2W0%0Z0e0k0I880R8z1r1t1v1x0Gdb5`1M3J1G0Q0-6Q0G7S0r2Y0#1,1x0m0G2Q0P7/0~0n1~0-2f0r0u2b0p2Q1~0k1g0b7p0G0E000p2?0G0hfH0@1~5{3t3/1W1Y1!1$1(1-1?251@2xeB118Re!5|0(1Kfd040!1~280UfF0GfA0b0v0I2jfp1}0=d,7ncRfJf81P0e0efs2t6Q0=0ufH0u0*15fD0=3s17fMg80U0n7/2Q0G0k0n0b0#0i6$4VfV7:1Z1#1%0Nf#241?1^e`5ya?egcLeHa|eGeQ6Kd;b,b4a@d{5^e#3t3%3sd,2?0=fxfT2T5yfWgFfZgI231;gLf)9}gPd*cFaqgSacgUeSavdLd^dNgYb^eW9i7_g%0,3%25g,0(060D3c1ifA0kfh0r0P2j0%gyfz0Gf70Gg2fi4,0phB2T0i0P0v7p2Wfk1~fNfjfp0k0B0Bd5hy0p000qg70=0n3=ee0=0#0`1w0=2T0^0G0%0$2FhA1/fNfHg7hA3k34hI0P0,0r6Qf/fce_hm0GhT1gfJ1i0vf{1~3si1gd0UgAfK1g0:h)iig70p0t0Gf^fFir2Tg/ie4 g=fYgHgJg`26g|9+g~g$5|h?0g2?i31N1If=h|e|0#0c2WiLfN0E0pise;1}f`fxh.5=7IiVie1e1ifNfNif0~2t2 fphz0,0=ixgDd-iBf!g_f%gM8.9-f-g(iOf;0dfHgAgn6C0P6QgAhBfF2bf80v0_1x0M0G1,il1=d6hAf88R0%hEgq0GhHhJ2V2t0v0Uja6^0,8X0;04.

###(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 : 5/5

.128013oèPf8gbr1a3tv=uàn9xsc)7qR/p0Od; lk5:+,y2éChw6e[(S]_Liêm.4-050E0U0m0k0#0H0u0G0v0H0k0u0u0o010m0#0B010406050u0p0%0%0k0i0N040X0b0H0p0~0b0r0G020k0%0B0F0G0z0U180i0y0p0U0u050A1517191b130B04051G1z1J0A1G130E0#0n0?0^0`0|0^0r0g0p0k0g0U0*0B0N0m0R1i0G0R0#0g0R0H1/0R0m11050.0h0H0U1S0_0{011.1:1=1:0m1{1}1_0m0i1H1*0?1e0u0B0k0r0|0O011 1U010e0:0U0r1m0U1_2h2j2o212r1}2u0%2w040a0G0d0i0b0B0b0u0#1h1j0,2f0i0i0U0v2R1z2y0r1H0A1*2%2b2d2c1`0E2A1V0#0r2t2O1_1P1R0@202;2?0r0b2`1_0B2W1H2#2%37142i1j2|2p300i180H1_0k1-2W0e0|030Z0Z0v310U1=2 0b0*0)0*0j110G0j1z0k383b123a2z3d213f3h3j3l0U3n013p3r3t3v2@3y0*2m040G0O3F3H2j3J2#2:013O0k3i1H3k0R3m3o3q3s0,3Y303!0l3C0l3*2!3I133.3M0|3;3?053^3`3U3|3X2=3Z3z0)3C0)451A473K3c1T3N0b3g3=3Q3_3S3{3W3~4k403z0J3C0J4q37483b3/4c4A4g3V3}3u4G3x3z0T3C0T4M4s494v4b4x3P3@3R3T4U4j3w3!0x3C0x4%3,4O3L4*3:4,4z4.4B4:4i4F4?3z0f3C0f4{2$4}4u2}504y4d4f4C4h4E4W580*0s3C0s5d3-4P4a5i4-4e4/4D4V3 4Y3A0C110j0C5v5f4Q515k5C5n5E4X3!0j3B045W5v1K351z2`2*0E2d2/5y4V2_1Q1H340U363I463,054V5@2z0#0E0|3q2#5V3Q5 615o5F640G2E0U675T5q5X454)5h0I110,0e5_2$4t3/0S3C6p5}5g3e0e110H0B0;0u0v6v6r5y10040W6G6j3e110m0U0t6Q0Z0k6M5x4 6J0M6v0G6H4 0r6P6R6T0h6W4~5h6J0w0K6v134r5`3.6601623b3!3$5B6|565p4l3#2n6c6e4=76710A3G0G7g6$6N3N6A1i1Y0U0p0i1y6_2$7i6X5h0b110o6#6%6:110V6.6x210%0#115L7s3%7B2p6l040e4x7A7j4b110Z7U7v2p0b6t042=7Z6/3e0h110i2j1#7F3/6J6L7M7O3N7-042D7=6I117^397V3:6*6S0U6U7 6Y110w7*7G0|7x040L8e3/7I5J8a7C040w0Y6@7=730Z633z424.8v6f76426b2v7a578D1_7e3%7h7`0|7Q7S0i8k5y6)040.0:1}0Z6-7M7u7+217$117)8$8O3:7|7/1X0U8o2p7@8@7H7J5Y8`0|6Z8T6(7|7~7_848_957!7k8W6+888#83998 8c917w118j8-848m8}988(9h8q6?7M6^9f5~606}8w6 4m659A74699E8F2F8H754H3y8K7f7h9S8.8V6Q1n9j7#7y9Y216J7E9r8f019p7L378%9*8Q7T9n9g85047Y9?9s018*7(0r9#4b8:7:8?9)7?818~8/6A2ta9979y9*9V9c89a6808qa19}9lan9p3Eak8b8q8s9w8u9G9C2j3!4J8Aaz8C9O4J9K6d9BaG5GaD3*9S9T849;8S9{ag6P0/0H8Z6VaV3/9~8,9.9Ua38=ada8at5hara.046!a$8U93aca:8^a/af4Q866Ta#b0al8da_4 8h9ma*9o8|asb5au6=8ta68v8x0*4!aE9M9Ibn788GaL7b9OboaPaQbA8.7Q0#6ob85hah87ajbg8p9(bL6O8WaYa!an8h0*aqbea?awbc9@8h0o7zbGbP6QbJ9e5^967Da99VbR9dbT11bVb)8{8na}9$110Y9v4Nay67bm4^bpbv8I9O4^aJbq5U3zc7bzbAcj9/b19b9Xb~9tbNb.9@b=8Y88b4cs9|6JbZ3Icl5yb$bWb}b!9|baan8V0H7m1w7p7rbOb 04cr6`ctaXcvbKcC8.bUcG9qcS9tcB4|c49Bbm5ac89Hcf0*5acdc99N5Gc;cickcD4 7Q3u0ua5c*016Jc24sbkazbm5sc=68c@5sc`c?5qdfc d08N84ahcod79%b;cYaZcwbYb^04b(cIag7|180ta?82cyaWcn0Ba?cV6qdrdxbSb{8gb_c(bfdLa7040Ya^dEcmcN1XcP7qdPdwbQcZcxcWczc0b7c3dcc59D5H9Fce6g5Idkdhe29Q8MbBdS7}cO7od.dVaodCcL6*dtdbb0bld~5We0c{brepe4aM5V6h8LaR9@7Q2W0m7pa0efcMeccQd/cpaa7}a|dua d!8Ub2dzeL6;c,5e6G0A5|5#5?5%5:1z0m5*e*2-2(0k1|e%0A5(1F6w3/2W0%0Z0e0k0I880R8z1r1t1v1x0Gda5`1M3J1G0Q0-6Q0G7S0r2Y0#1,1x0m0G2Q0P7/0~0n1~0-2f0r0u2b0p2Q1~0k1g0b7p0G0E000p2?0G0hfG0@1~5{3t3/1W1Y1!1$1(1-1?251@2xeA118ReZ5|0(1Kfc040!1~280UfE0Gfz0b0v0I2jfo1}0=d+7ncQfIf71P0e0efr2t6Q0=0ufG0u0*15fC0=3s17fLg70U0n7/2Q0G0k0n0b0#0i6$4VfU7:1Z1#1%0Nf!241?1^e_5ya=efcKeGa{eFeP6Kd:b+b3a?d`5^e!3t3%3sd+2?0=fwfS2T5yfVgEfYgH231;gKf(9|gOd)cEapgRabgTeRaudKd@dMgXb@eV9i7_g$0,3%25g+0(060D3c1ifz0kfg0r0P2j0%gxfy0Gf60Gg1fh4,0phA2T0i0P0v7p2Wfj1~fMfifo0k0B0Bd4hx0p000qg60=0n3=ed0=0#0`1w0=2T0^0G0%0$2Fhz1/fMfGg6hz3k34hH0P0,0r6Qf.fbe^hl0GhS1gfI1i0vf`1~3si0gc0UgzfJ1g0:h(ihg60p0t0Gf@fEiq2Tg.id4 g;fXgGgIg_26g{9*g}g#5|h=0g2?i21N1If;h{e{0#0c2WiKfM0E0pire:1}f_fwh-5=7IiUid1e1ifMfMie0~2t2 fohy0,0=iwgCd,iAfZg^f$gL8.9,f,g%iNf:0dfGgzgm6C0P6QgzhAfE2bf70v0_1x0M0G1,ik1=d5hzf78R0%hDgp0GhGhI2V2t0v0Uj96^0,8X0;04.

Crédits: page modifiée d'après codex, de Nicolas Révéret et Franck Chambon.