{"id":690,"date":"2022-07-18T09:08:48","date_gmt":"2022-07-18T08:08:48","guid":{"rendered":"https:\/\/blog.univ-angers.fr\/mathsinfo\/?p=690"},"modified":"2022-07-18T14:45:06","modified_gmt":"2022-07-18T13:45:06","slug":"carte-de-france-en-python-500-octets","status":"publish","type":"post","link":"https:\/\/blog.univ-angers.fr\/mathsinfo\/2022\/07\/18\/carte-de-france-en-python-500-octets\/","title":{"rendered":"Carte de France en Python 500 octets"},"content":{"rendered":"\n<p><a href=\"https:\/\/twitter.com\/NumWorksFR\/status\/1547498636619223040\" data-type=\"URL\" data-id=\"https:\/\/twitter.com\/NumWorksFR\/status\/1547498636619223040\" target=\"_blank\" rel=\"noreferrer noopener\">Suite \u00e0 un Tweet de NumWorks<\/a> pr\u00e9sentant le visuel d&rsquo;une <strong>carte de France<\/strong>, j&rsquo;ai lanc\u00e9 le <strong>challenge<\/strong> de r\u00e9aliser une carte aussi r\u00e9aliste que possible (ou faussement r\u00e9aliste) <strong>en Python et en moins de 500 octets<\/strong>.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full is-resized\"><a href=\"https:\/\/blog.univ-angers.fr\/mathsinfo\/files\/2022\/07\/image.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/blog.univ-angers.fr\/mathsinfo\/files\/2022\/07\/image.png\" alt=\"\" class=\"wp-image-691\" width=\"309\" height=\"385\" \/><\/a><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Retour dans les ann\u00e9es 80<\/h2>\n\n\n\n<p>Dans les ann\u00e9es 80 est sorti un petit ordinateur individuel, le <strong>ZX-81<\/strong>. Il n&rsquo;avait que 1Ko de RAM (soit 1000 caract\u00e8res) mais permettait de s&rsquo;initier \u00e0 la programmation et de cr\u00e9er quelques jeux. L&rsquo;achat d&rsquo;une extension 16Ko ou 32Ko \u00e9tait cependant assez rapidement n\u00e9cessaire.<\/p>\n\n\n\n<p>Voici un programme propos\u00e9 dans le livre \u00ab\u00a0Pilotez votre ZX 81\u00a0\u00bb de Patrick Gueule :<\/p>\n\n\n\n<figure class=\"wp-block-image size-full is-resized\"><a href=\"https:\/\/blog.univ-angers.fr\/mathsinfo\/files\/2022\/07\/image-1.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/blog.univ-angers.fr\/mathsinfo\/files\/2022\/07\/image-1.png\" alt=\"\" class=\"wp-image-694\" width=\"358\" height=\"462\" \/><\/a><\/figure>\n\n\n\n<p>La machine poss\u00e9dait des caract\u00e8res semi-graphiques, comme par exemple \u25e7 \u25e8. L&rsquo;astuce dans ce programme est de m\u00e9moriser le nombre d&rsquo;espaces \u00e0 afficher \u00e0 partir de la gauche puis le(s) caract\u00e8re(s) semi-graphique(s), \u00e0 nouveau le nombre d&rsquo;espaces ensuite le(s) caract\u00e8re(s) et terminer par 0 pour passer \u00e0 la ligne suivante. Ainsi le 7780 de la variable A$ indique qu&rsquo;il faut afficher 7+7+8=22 espaces et revenir \u00e0 la ligne (ligne blanche au-dessus de la carte). Ensuite 6+5=11 espaces puis 3 caract\u00e8res semi-graphiques et retour \u00e0 la ligne :<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/blog.univ-angers.fr\/mathsinfo\/files\/2022\/07\/image-3.png\"><img loading=\"lazy\" decoding=\"async\" width=\"600\" height=\"196\" src=\"https:\/\/blog.univ-angers.fr\/mathsinfo\/files\/2022\/07\/image-3.png\" alt=\"\" class=\"wp-image-698\" srcset=\"https:\/\/blog.univ-angers.fr\/mathsinfo\/files\/2022\/07\/image-3.png 600w, https:\/\/blog.univ-angers.fr\/mathsinfo\/files\/2022\/07\/image-3-300x98.png 300w, https:\/\/blog.univ-angers.fr\/mathsinfo\/files\/2022\/07\/image-3-500x163.png 500w\" sizes=\"auto, (max-width: 600px) 100vw, 600px\" \/><\/a><\/figure>\n\n\n\n<p>Remarquez que les caract\u00e8res semi-graphiques ayant une dimension de 2&#215;2, cela permet d&rsquo;afficher 2 rang\u00e9es de la carte \u00e0 la fois.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">M\u00eame id\u00e9e en Python<\/h2>\n\n\n\n<p>Dessinons la carte de France en tapant des <strong>1<\/strong> dans certaines cellules d&rsquo;Excel (pour cela importez une image de la France dans <strong>Mise en Page &#8211; Arri\u00e8re Plan<\/strong>, s\u00e9lectionnez toutes les cellules puis <strong>Accueil &#8211; Mise en forme conditionnelle &#8211; R\u00e8gle de surlignage<\/strong> &#8211; Egal \u00e0 <strong>1<\/strong> &#8211; Mettre une couleur de <strong>remplissage<\/strong>). <\/p>\n\n\n\n<figure class=\"wp-block-image size-full is-resized\"><a href=\"https:\/\/blog.univ-angers.fr\/mathsinfo\/files\/2022\/07\/image-4.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/blog.univ-angers.fr\/mathsinfo\/files\/2022\/07\/image-4.png\" alt=\"\" class=\"wp-image-700\" width=\"391\" height=\"365\" \/><\/a><\/figure>\n\n\n\n<p>A c\u00f4t\u00e9 de la carte tapez la formule <strong>=A1+2*B1+4*A2+8*B2<\/strong>. Cela permet de convertir les 4 cellules (jaune sur la carte) en un nombre entre 1 et 1+2+4+8=15. <\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/blog.univ-angers.fr\/mathsinfo\/files\/2022\/07\/image-5.png\"><img loading=\"lazy\" decoding=\"async\" width=\"255\" height=\"122\" src=\"https:\/\/blog.univ-angers.fr\/mathsinfo\/files\/2022\/07\/image-5.png\" alt=\"\" class=\"wp-image-702\" \/><\/a><\/figure>\n\n\n\n<p>On peut alors \u00e9tendre cette formule horizontalement et verticalement pour recouvrir toute la carte.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/blog.univ-angers.fr\/mathsinfo\/files\/2022\/07\/image-6.png\"><img loading=\"lazy\" decoding=\"async\" width=\"869\" height=\"340\" src=\"https:\/\/blog.univ-angers.fr\/mathsinfo\/files\/2022\/07\/image-6.png\" alt=\"\" class=\"wp-image-703\" srcset=\"https:\/\/blog.univ-angers.fr\/mathsinfo\/files\/2022\/07\/image-6.png 869w, https:\/\/blog.univ-angers.fr\/mathsinfo\/files\/2022\/07\/image-6-300x117.png 300w, https:\/\/blog.univ-angers.fr\/mathsinfo\/files\/2022\/07\/image-6-768x300.png 768w, https:\/\/blog.univ-angers.fr\/mathsinfo\/files\/2022\/07\/image-6-500x196.png 500w\" sizes=\"auto, (max-width: 869px) 100vw, 869px\" \/><\/a><\/figure>\n\n\n\n<p>Si on \u00e9crit le <strong>9<\/strong> de la premi\u00e8re ligne en binaire :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&gt; bin(9)\n'0b1001'<\/code><\/pre>\n\n\n\n<p>Cela signifie que les cellules 1 et 4 contiennent un 1 et les autres un 0. Il s&rsquo;agit du caract\u00e8re ci-dessous :<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/blog.univ-angers.fr\/mathsinfo\/files\/2022\/07\/image-7.png\"><img loading=\"lazy\" decoding=\"async\" width=\"145\" height=\"85\" src=\"https:\/\/blog.univ-angers.fr\/mathsinfo\/files\/2022\/07\/image-7.png\" alt=\"\" class=\"wp-image-704\" \/><\/a><\/figure>\n\n\n\n<p>On est alors dans la m\u00eame configuration que sur le ZX-81, on doit compter le nombre d&rsquo;espaces (les 0) puis un caract\u00e8re graphique cod\u00e9 sur 4 cases.<\/p>\n\n\n\n<p>Voici le d\u00e9but du codage :<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/blog.univ-angers.fr\/mathsinfo\/files\/2022\/07\/image-8.png\"><img loading=\"lazy\" decoding=\"async\" width=\"806\" height=\"183\" src=\"https:\/\/blog.univ-angers.fr\/mathsinfo\/files\/2022\/07\/image-8.png\" alt=\"\" class=\"wp-image-706\" srcset=\"https:\/\/blog.univ-angers.fr\/mathsinfo\/files\/2022\/07\/image-8.png 806w, https:\/\/blog.univ-angers.fr\/mathsinfo\/files\/2022\/07\/image-8-300x68.png 300w, https:\/\/blog.univ-angers.fr\/mathsinfo\/files\/2022\/07\/image-8-768x174.png 768w, https:\/\/blog.univ-angers.fr\/mathsinfo\/files\/2022\/07\/image-8-500x114.png 500w\" sizes=\"auto, (max-width: 806px) 100vw, 806px\" \/><\/a><\/figure>\n\n\n\n<p>Les lettres <strong>F<\/strong> et <strong>I<\/strong> de la premi\u00e8re ligne sont simplement les <strong>6<\/strong>e et <strong>9<\/strong>e lettres de l&rsquo;alphabet et permettent donc de coder les nombres 6 et 9.<\/p>\n\n\n\n<p>Le caract\u00e8re <strong>*<\/strong> a <strong>42<\/strong> comme code Ascii, notre r\u00e9f\u00e9rence \u00e9tant le code <strong>33<\/strong>, ce qui fait une diff\u00e9rence de 9 soit 9 espaces.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&gt; ord('*')\n42\n&gt; chr(33)\n'!'<\/code><\/pre>\n\n\n\n<p>Enfin, j&rsquo;utiliserai le caract\u00e8re &lsquo;!&rsquo; pour les fins de ligne. Le contour de la carte peut donc \u00eatre traduit par :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>FR = '*FI!*E,ID!(...'<\/code><\/pre>\n\n\n\n<p>Pour le programme principal, il suffit, suivant le code Ascii, de d\u00e9cider si l&rsquo;on doit <strong>revenir \u00e0 la ligne<\/strong> (caract\u00e8re &lsquo;!&rsquo; de code 33), se d\u00e9caler suivant l&rsquo;axe des x d&rsquo;un certain nombre d&rsquo;<strong>espaces<\/strong> ou afficher un <strong>caract\u00e8re semi-graphique<\/strong> :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>x, y = 0, 0\nfor s in FR:\n n = ord(s)\n if n == 33: x, y = 0, y + 10        # Retour \u00e0 la ligne\n elif n &lt; 55: x = 10 * (n - 33)      # 10 pixels par \"espace\"\n else: \n  car(n - 64)   # Affichage du caract\u00e8re semi-graphique\n  x += 10       # Et d\u00e9calage \u00e0 droite de 10 pixels<\/code><\/pre>\n\n\n\n<p>Pour la fonction <strong>car<\/strong>, soit on d\u00e9compose le param\u00e8tre en binaire pour savoir quelles cases on doit remplir, soit on les r\u00e9cup\u00e8re petit \u00e0 petit. Par exemple, si le caract\u00e8re semi-graphique est <strong>L<\/strong> :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&gt; ord('L')      # on r\u00e9cup\u00e8re son code Ascii\n76\n&gt; 76 - 64       \n12              # 12e lettre\n&gt; bin(12)       \n'0b1100'    # 2 premi\u00e8res cases noires et suivantes blanches\n&gt; 12 &gt;&gt; 0 &amp; 1   # On peut aussi r\u00e9cup\u00e9rer 1-1-0-0 petit \u00e0 petit \n0\n&gt; 12 &gt;&gt; 1 &amp; 1\n0\n&gt; 12 &gt;&gt; 2 &amp; 1\n1\n&gt; 12 &gt;&gt; 3 &amp; 1\n1<\/code><\/pre>\n\n\n\n<p>Fonction <strong>car<\/strong> avec des carr\u00e9s noirs de 5*5 pixels :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>def car(x, y, n):\n for i in range(4):\n  if n &gt;&gt; i &amp; 1:\n   fill_rect(x + i % 2 * 5, y + i \/\/ 2 * 5, 5, 5, (0,0,0))<\/code><\/pre>\n\n\n\n<p><a href=\"https:\/\/my.numworks.com\/python\/schraf\/france\" target=\"_blank\" rel=\"noreferrer noopener\">Programme final ici<\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Avec la tortue<\/h2>\n\n\n\n<p>Une autre id\u00e9e est de parcourir le contour de la carte avec la tortue. Pour rester dans les 500 octets impos\u00e9s, il ne faudra utiliser que quelques points strat\u00e9giques.<\/p>\n\n\n\n<p>Pour cela on peut ouvrir la carte de France dans Gimp et utiliser l&rsquo;outil Chemin :<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/blog.univ-angers.fr\/mathsinfo\/files\/2022\/07\/image-9.png\"><img loading=\"lazy\" decoding=\"async\" width=\"581\" height=\"306\" src=\"https:\/\/blog.univ-angers.fr\/mathsinfo\/files\/2022\/07\/image-9.png\" alt=\"\" class=\"wp-image-712\" srcset=\"https:\/\/blog.univ-angers.fr\/mathsinfo\/files\/2022\/07\/image-9.png 581w, https:\/\/blog.univ-angers.fr\/mathsinfo\/files\/2022\/07\/image-9-300x158.png 300w, https:\/\/blog.univ-angers.fr\/mathsinfo\/files\/2022\/07\/image-9-500x263.png 500w\" sizes=\"auto, (max-width: 581px) 100vw, 581px\" \/><\/a><\/figure>\n\n\n\n<p>On note les coordonn\u00e9es des points dans un tableur. L&rsquo;id\u00e9e est de partir d&rsquo;un des points du contour puis de d\u00e9placer la tortue en utilisant uniquement les diff\u00e9rences entre les coordonn\u00e9es :<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/blog.univ-angers.fr\/mathsinfo\/files\/2022\/07\/image-10.png\"><img loading=\"lazy\" decoding=\"async\" width=\"448\" height=\"155\" src=\"https:\/\/blog.univ-angers.fr\/mathsinfo\/files\/2022\/07\/image-10.png\" alt=\"\" class=\"wp-image-713\" srcset=\"https:\/\/blog.univ-angers.fr\/mathsinfo\/files\/2022\/07\/image-10.png 448w, https:\/\/blog.univ-angers.fr\/mathsinfo\/files\/2022\/07\/image-10-300x104.png 300w\" sizes=\"auto, (max-width: 448px) 100vw, 448px\" \/><\/a><\/figure>\n\n\n\n<p>Par exemple, pour passer du point (64,58) au point (62, 61) on se d\u00e9cale du vecteur (-2,3). L&rsquo;int\u00e9r\u00eat ? On utilisera moins de caract\u00e8res pour m\u00e9moriser les coordonn\u00e9es !<\/p>\n\n\n\n<p>Voici le codage de la carte, sachant que le point initial est en (90,-60) qui correspond au nord de la Corse<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>F = '18!23!3!30...'<\/code><\/pre>\n\n\n\n<p>D\u00e9placer la tortue du vecteur (1,8) puis (-2,3) puis (-3,-30) etc.<\/p>\n\n\n\n<p>Ce qui donne cette version :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>from turtle import *\n\nF = '18!23!3!30!53!11!2!8!5!55!32!9!3!5305!40!6!3!8!1!3!33!D22!2!5!4!6!1!4!4!3!4!1!2!12!1!2!10!28!11260!2!720124!12!25!11!73098E5!29!66043!223!1B51'\n\ndef f(s = 1): \n global i\n if F&#091;i] == '!': i, s = i + 1, -1\n i += 1\n return s * int(F&#091;i - 1], 16)\n\nx = y = i = 0\npenup()\nwhile i &lt; len(F):\n goto(90 + 3 * x, -60 - 3 * y)\n pendown()\n x += f()\n y += f()\nhideturtle()<\/code><\/pre>\n\n\n\n<p>Mais le r\u00e9sultat n&rsquo;est pas tr\u00e8s joli car trop rectiligne et la Corse est reli\u00e9e \u00e0 la m\u00e9tropole<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/blog.univ-angers.fr\/mathsinfo\/files\/2022\/07\/france1.png\"><img loading=\"lazy\" decoding=\"async\" width=\"320\" height=\"240\" src=\"https:\/\/blog.univ-angers.fr\/mathsinfo\/files\/2022\/07\/france1.png\" alt=\"\" class=\"wp-image-716\" srcset=\"https:\/\/blog.univ-angers.fr\/mathsinfo\/files\/2022\/07\/france1.png 320w, https:\/\/blog.univ-angers.fr\/mathsinfo\/files\/2022\/07\/france1-300x225.png 300w\" sizes=\"auto, (max-width: 320px) 100vw, 320px\" \/><\/a><\/figure>\n\n\n\n<p>On va ajouter de <strong>l&rsquo;al\u00e9atoire<\/strong> en faisant varier la trajectoire entre 2 coordonn\u00e9es. Pour cela on doit d\u00e9composer le segment (x1,y1) vers (x2,y2) en sous-segments :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>for j in range(9):   # D\u00e9composition en 9 \u00e9tapes...\n  goto(90 + g(u,x,j),-60 - g(v,y,j))  # ...entre (u,v) et (x,y)\n\ndef g(a, b, j): return 3 * (a + (b - a) * j \/ 9)   # Interpolation<\/code><\/pre>\n\n\n\n<p>Et avec de l&rsquo;al\u00e9atoire :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>def g(a,b,j): return 3 * a + 2 * random() + (b - a) * j \/ 3<\/code><\/pre>\n\n\n\n<p>Concernant la s\u00e9paration avec la Corse, l&rsquo;astuce utilis\u00e9e est qu&rsquo;avec la NumWorks <strong>pensize(0)<\/strong> ne trace pas de trait. Ainsi en ajoutant :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>pensize(not(18 &lt; i &lt; 23))<\/code><\/pre>\n\n\n\n<p>On aura un trait d&rsquo;\u00e9paisseur 1 sauf si <strong>i<\/strong> est entre 18 et 23 qui correspond au trait reliant la Corse.<\/p>\n\n\n\n<p>Enfin, on peut dessiner de petits cercles \u00e0 chaque \u00e9tapes plut\u00f4t qu&rsquo;un trait simple, <a href=\"https:\/\/my.numworks.com\/python\/schraf\/france2\" target=\"_blank\" rel=\"noreferrer noopener\">on obtient finalement ce script<\/a> qui fait exactement 500 octets avec le r\u00e9sultat suivant :<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/blog.univ-angers.fr\/mathsinfo\/files\/2022\/07\/image-11.png\"><img loading=\"lazy\" decoding=\"async\" width=\"320\" height=\"240\" src=\"https:\/\/blog.univ-angers.fr\/mathsinfo\/files\/2022\/07\/image-11.png\" alt=\"\" class=\"wp-image-718\" srcset=\"https:\/\/blog.univ-angers.fr\/mathsinfo\/files\/2022\/07\/image-11.png 320w, https:\/\/blog.univ-angers.fr\/mathsinfo\/files\/2022\/07\/image-11-300x225.png 300w\" sizes=\"auto, (max-width: 320px) 100vw, 320px\" \/><\/a><\/figure>\n","protected":false},"excerpt":{"rendered":"<p>Suite \u00e0 un Tweet de NumWorks pr\u00e9sentant le visuel d&rsquo;une carte de France, j&rsquo;ai lanc\u00e9 le challenge de r\u00e9aliser une carte aussi r\u00e9aliste que possible (ou faussement r\u00e9aliste) en Python et en moins de 500 octets. Retour dans les ann\u00e9es &hellip; <a href=\"https:\/\/blog.univ-angers.fr\/mathsinfo\/2022\/07\/18\/carte-de-france-en-python-500-octets\/\">Continuer la lecture <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":4913,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[6],"tags":[],"class_list":["post-690","post","type-post","status-publish","format-standard","hentry","category-twitter"],"_links":{"self":[{"href":"https:\/\/blog.univ-angers.fr\/mathsinfo\/wp-json\/wp\/v2\/posts\/690","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.univ-angers.fr\/mathsinfo\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.univ-angers.fr\/mathsinfo\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.univ-angers.fr\/mathsinfo\/wp-json\/wp\/v2\/users\/4913"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.univ-angers.fr\/mathsinfo\/wp-json\/wp\/v2\/comments?post=690"}],"version-history":[{"count":27,"href":"https:\/\/blog.univ-angers.fr\/mathsinfo\/wp-json\/wp\/v2\/posts\/690\/revisions"}],"predecessor-version":[{"id":730,"href":"https:\/\/blog.univ-angers.fr\/mathsinfo\/wp-json\/wp\/v2\/posts\/690\/revisions\/730"}],"wp:attachment":[{"href":"https:\/\/blog.univ-angers.fr\/mathsinfo\/wp-json\/wp\/v2\/media?parent=690"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.univ-angers.fr\/mathsinfo\/wp-json\/wp\/v2\/categories?post=690"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.univ-angers.fr\/mathsinfo\/wp-json\/wp\/v2\/tags?post=690"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}