<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	>

<channel>
	<title>blog</title>
	<atom:link href="http://blog.vfiack.fr/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.vfiack.fr</link>
	<description>blog.vfiack.fr</description>
	<pubDate>Fri, 27 Apr 2012 20:12:12 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.7</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Un interpreteur / optimiseur de BrainFuck en OCaml</title>
		<link>http://blog.vfiack.fr/120-un-interpreteur-optimiseur-de-brainfuck-en-ocaml/</link>
		<comments>http://blog.vfiack.fr/120-un-interpreteur-optimiseur-de-brainfuck-en-ocaml/#comments</comments>
		<pubDate>Mon, 23 Apr 2012 15:20:39 +0000</pubDate>
		<dc:creator>vfiack</dc:creator>
		
		<category><![CDATA[Développement]]></category>

		<category><![CDATA[brainfuck]]></category>

		<category><![CDATA[ocaml]]></category>

		<guid isPermaLink="false">http://blog.vfiack.fr/?p=120</guid>
		<description><![CDATA[Le langage BrainFuck est un langage ésotérique (comprendre par la qu&#8217;il ne sert pas a grand chose), minimaliste.
Il suppose une machine avec un ruban de mémoire, un pointeur sur une cellule de cette mémoire, et ne contient que 8 opérations, chacune représentée par un caractère dans le code source :


&#62;
incrémente le pointeur


&#60;
décrémente le pointeur


+
incrémente la [...]]]></description>
			<content:encoded><![CDATA[<p>Le langage <a href="http://fr.wikipedia.org/wiki/Brainfuck">BrainFuck</a> est un langage ésotérique (comprendre par la qu&#8217;il ne sert pas a grand chose), minimaliste.</p>
<p>Il suppose une machine avec un ruban de mémoire, un pointeur sur une cellule de cette mémoire, et ne contient que 8 opérations, chacune représentée par un caractère dans le code source :</p>
<table>
<tr>
<td>&gt;</td>
<td>incrémente le pointeur</td>
</tr>
<tr>
<td>&lt;</td>
<td>décrémente le pointeur</td>
</tr>
<tr>
<td>+</td>
<td>incrémente la valeur de la cellule sur laquelle est positionnée le pointeur</td>
</tr>
<tr>
<td>-</td>
<td>décrémente la valeur de la cellule courante</td>
</tr>
<tr>
<td>.</td>
<td>affiche la valeur ascii de la cellule courante</td>
</tr>
<tr>
<td>,</td>
<td>lit un caractère et stocke sa valeur ascii dans la cellule courante</td>
</tr>
<tr>
<td>[</td>
<td>saute a l'instruction après le ] correspondant si la cellule courante est à 0.</td>
</tr>
<tr>
<td>]</td>
<td>retourne au [ correspondant si la cellule courante est différente de 0.</td>
</tr>
</table>
<p>En résumé, &gt; et &lt; font bouger un pointeur, + et - modifient la valeur de la cellule courante, . et , servent d'entrées-sorties, et [ ] fait une boucle.</p>
<p>A titre d&#8217;exemple, ce programme affiche &#8220;Hello World!&#8221; : <a href="https://bitbucket.org/vfiack/ocaml-toys/raw/07f3f3c1c9fa/brainfuck/hello.bf">hello.bf</a></p>
<p>Voici le <a href="https://bitbucket.org/vfiack/ocaml-toys/src/07f3f3c1c9fa/brainfuck/brainfuck.ml">code complet</a> de l&#8217;interpréteur que cet article vise a expliquer.</p>
<h3>Interpréteur basique, sans optimisations</h3>
<p><strong>Représentation des opérations basiques de BrainFuck</strong></p>
<p>La première chose à faire, c&#8217;est de décider de la représentation interne des opérations. J&#8217;ai choisi de regrouper les opérations de déplacement et de modification, et de représenter [..] comme une sous liste d&#8217;opération.</p>

<div class="wp_syntax"><div class="code"><pre class="ocaml ocaml" style="font-family:monospace;">  <span style="color: #06c; font-weight: bold;">type</span> operation <span style="color: #a52a2a;">=</span>
    | Move <span style="color: #06c; font-weight: bold;">of</span> int 
    | Add <span style="color: #06c; font-weight: bold;">of</span> int
    | Output
    | Input
    | Loop <span style="color: #06c; font-weight: bold;">of</span> operation list</pre></div></div>

<p><strong>Conversion du code BF en arbre d&#8217;opérations</strong></p>
<p>Maintenant, il nous faut un moyen de convertir le source BrainFuck en un arbre d&#8217;opérations, en utilisant le type que nous venons de définir. En dehors des boucles, la conversion est assez directe.</p>

<div class="wp_syntax"><div class="code"><pre class="ocaml ocaml" style="font-family:monospace;">  <span style="color: #06c; font-weight: bold;">let</span> <span style="color: #06c; font-weight: bold;">rec</span> build_ast tokens <span style="color: #a52a2a;">=</span>
    <span style="color: #06c; font-weight: bold;">let</span> <span style="color: #06c; font-weight: bold;">rec</span> loop tokens acc <span style="color: #a52a2a;">=</span>
      <span style="color: #06c; font-weight: bold;">match</span> tokens <span style="color: #06c; font-weight: bold;">with</span>
      | <span style="color: #6c6;">&#91;</span><span style="color: #6c6;">&#93;</span> <span style="color: #a52a2a;">-&gt;</span> acc
      | <span style="color: #a52a2a;">'&gt;'</span> <span style="color: #a52a2a;">::</span> rest <span style="color: #a52a2a;">-&gt;</span> loop rest <span style="color: #6c6;">&#40;</span>Move <span style="color: #c6c;">1</span> <span style="color: #a52a2a;">::</span> acc<span style="color: #6c6;">&#41;</span>
      | <span style="color: #a52a2a;">'&lt;'</span> <span style="color: #a52a2a;">::</span> rest <span style="color: #a52a2a;">-&gt;</span> loop rest <span style="color: #6c6;">&#40;</span>Move <span style="color: #6c6;">&#40;</span><span style="color: #a52a2a;">-</span><span style="color: #c6c;">1</span><span style="color: #6c6;">&#41;</span> <span style="color: #a52a2a;">::</span> acc<span style="color: #6c6;">&#41;</span>
      | <span style="color: #a52a2a;">'+'</span> <span style="color: #a52a2a;">::</span> rest <span style="color: #a52a2a;">-&gt;</span> loop rest <span style="color: #6c6;">&#40;</span>Add <span style="color: #c6c;">1</span> <span style="color: #a52a2a;">::</span> acc<span style="color: #6c6;">&#41;</span>
      | <span style="color: #a52a2a;">'-'</span> <span style="color: #a52a2a;">::</span> rest <span style="color: #a52a2a;">-&gt;</span> loop rest <span style="color: #6c6;">&#40;</span>Add <span style="color: #6c6;">&#40;</span><span style="color: #a52a2a;">-</span><span style="color: #c6c;">1</span><span style="color: #6c6;">&#41;</span> <span style="color: #a52a2a;">::</span> acc<span style="color: #6c6;">&#41;</span>
      | <span style="color: #a52a2a;">'.'</span> <span style="color: #a52a2a;">::</span> rest <span style="color: #a52a2a;">-&gt;</span> loop rest <span style="color: #6c6;">&#40;</span>Output <span style="color: #a52a2a;">::</span> acc<span style="color: #6c6;">&#41;</span>
      | <span style="color: #a52a2a;">'</span>,<span style="color: #a52a2a;">'</span> <span style="color: #a52a2a;">::</span> rest <span style="color: #a52a2a;">-&gt;</span> loop rest <span style="color: #6c6;">&#40;</span>Input <span style="color: #a52a2a;">::</span> acc<span style="color: #6c6;">&#41;</span>
      | <span style="color: #a52a2a;">'</span><span style="color: #6c6;">&#91;</span><span style="color: #a52a2a;">'</span> <span style="color: #a52a2a;">::</span> rest <span style="color: #a52a2a;">-&gt;</span>
          <span style="color: #06c; font-weight: bold;">let</span> sublist, rest <span style="color: #a52a2a;">=</span> build_loop tokens <span style="color: #06c; font-weight: bold;">in</span>
          <span style="color: #06c; font-weight: bold;">let</span> cond <span style="color: #a52a2a;">=</span> build_ast sublist <span style="color: #06c; font-weight: bold;">in</span>
          loop rest <span style="color: #6c6;">&#40;</span><span style="color: #6c6;">&#40;</span>Loop cond<span style="color: #6c6;">&#41;</span> <span style="color: #a52a2a;">::</span> acc<span style="color: #6c6;">&#41;</span>
      | <span style="color: #a52a2a;">'</span><span style="color: #6c6;">&#93;</span><span style="color: #a52a2a;">'</span> <span style="color: #a52a2a;">::</span> rest <span style="color: #a52a2a;">-&gt;</span> <span style="color: #06c; font-weight: bold;">failwith</span> <span style="color: #3cb371;">&quot;Close should have been consumed by build_loop&quot;</span>
      | _ <span style="color: #a52a2a;">::</span> rest <span style="color: #a52a2a;">-&gt;</span> loop rest acc
    <span style="color: #06c; font-weight: bold;">in</span>
    <span style="color: #06c; font-weight: bold;">List</span><span style="color: #a52a2a;">.</span><span style="color: #060;">rev</span> <span style="color: #6c6;">&#40;</span>loop tokens <span style="color: #6c6;">&#91;</span><span style="color: #6c6;">&#93;</span><span style="color: #6c6;">&#41;</span></pre></div></div>

<p>Je n&#8217;ai pas cité la fonction build_loop pour des raisons de place, mais elle est disponible dans le source complet.</p>
<p><strong>Interprétation dans une machine virtuelle basique, avec sa mémoire fixe et son unique pointeur</strong></p>
<p>Voilà notre arbre d&#8217;opérations, il nous reste à l&#8217;exécuter.</p>
<p>On utilise une &#8220;machine virtuelle&#8221;, avec sa mémoire et son pointeur :</p>

<div class="wp_syntax"><div class="code"><pre class="ocaml ocaml" style="font-family:monospace;">  <span style="color: #06c; font-weight: bold;">let</span> memory <span style="color: #a52a2a;">=</span> <span style="color: #06c; font-weight: bold;">Array</span><span style="color: #a52a2a;">.</span><span style="color: #060;">make</span> <span style="color: #c6c;">30</span>_000 0
  <span style="color: #06c; font-weight: bold;">let</span> pointer <span style="color: #a52a2a;">=</span> <span style="color: #06c; font-weight: bold;">ref</span> 0</pre></div></div>

<p>Par simplification, la mémoire est limitée a 30000 cellules, sous forme de tableau plutôt que de ruban.</p>
<p>Les fonctions de base, qui correspondent aux opérations de BF :</p>

<div class="wp_syntax"><div class="code"><pre class="ocaml ocaml" style="font-family:monospace;">  <span style="color: #06c; font-weight: bold;">let</span> move i <span style="color: #a52a2a;">=</span> pointer <span style="color: #a52a2a;">:=</span> <span style="color: #a52a2a;">!</span>pointer <span style="color: #a52a2a;">+</span> i
&nbsp;
  <span style="color: #06c; font-weight: bold;">let</span> add i <span style="color: #a52a2a;">=</span> memory<span style="color: #a52a2a;">.</span><span style="color: #6c6;">&#40;</span><span style="color: #a52a2a;">!</span>pointer<span style="color: #6c6;">&#41;</span> <span style="color: #a52a2a;">&lt;-</span> memory<span style="color: #a52a2a;">.</span><span style="color: #6c6;">&#40;</span><span style="color: #a52a2a;">!</span>pointer<span style="color: #6c6;">&#41;</span> <span style="color: #a52a2a;">+</span> i
&nbsp;
  <span style="color: #06c; font-weight: bold;">let</span> <span style="color: #06c; font-weight: bold;">output</span> <span style="color: #6c6;">&#40;</span><span style="color: #6c6;">&#41;</span> <span style="color: #a52a2a;">=</span> <span style="color: #06c; font-weight: bold;">Printf</span><span style="color: #a52a2a;">.</span><span style="color: #060;">printf</span> <span style="color: #3cb371;">&quot;%c%!&quot;</span> <span style="color: #6c6;">&#40;</span><span style="color: #06c; font-weight: bold;">char_of_int</span> memory<span style="color: #a52a2a;">.</span><span style="color: #6c6;">&#40;</span><span style="color: #a52a2a;">!</span>pointer<span style="color: #6c6;">&#41;</span><span style="color: #6c6;">&#41;</span>
&nbsp;
  <span style="color: #06c; font-weight: bold;">let</span> <span style="color: #06c; font-weight: bold;">input</span> <span style="color: #6c6;">&#40;</span><span style="color: #6c6;">&#41;</span> <span style="color: #a52a2a;">=</span>
    <span style="color: #06c; font-weight: bold;">let</span> c <span style="color: #a52a2a;">=</span> <span style="color: #06c; font-weight: bold;">input_char</span> <span style="color: #06c; font-weight: bold;">stdin</span> <span style="color: #06c; font-weight: bold;">in</span>
    memory<span style="color: #a52a2a;">.</span><span style="color: #6c6;">&#40;</span><span style="color: #a52a2a;">!</span>pointer<span style="color: #6c6;">&#41;</span> <span style="color: #a52a2a;">&lt;-</span> <span style="color: #06c; font-weight: bold;">int_of_char</span> c</pre></div></div>

<p>Et enfin, l&#8217;exécution d&#8217;une liste d&#8217;opérations, obtenue à partir du source BF.</p>

<div class="wp_syntax"><div class="code"><pre class="ocaml ocaml" style="font-family:monospace;">  <span style="color: #06c; font-weight: bold;">let</span> <span style="color: #06c; font-weight: bold;">rec</span> exec ast <span style="color: #a52a2a;">=</span>
    <span style="color: #06c; font-weight: bold;">let</span> exec_node <span style="color: #a52a2a;">=</span> <span style="color: #06c; font-weight: bold;">function</span>
      | Move i <span style="color: #a52a2a;">-&gt;</span> move i
      | Add i <span style="color: #a52a2a;">-&gt;</span> add i
      | Output <span style="color: #a52a2a;">-&gt;</span> <span style="color: #06c; font-weight: bold;">output</span> <span style="color: #6c6;">&#40;</span><span style="color: #6c6;">&#41;</span>
      | Input <span style="color: #a52a2a;">-&gt;</span> <span style="color: #06c; font-weight: bold;">input</span> <span style="color: #6c6;">&#40;</span><span style="color: #6c6;">&#41;</span>
      | Loop nodes <span style="color: #a52a2a;">-&gt;</span>
          <span style="color: #06c; font-weight: bold;">while</span> memory<span style="color: #a52a2a;">.</span><span style="color: #6c6;">&#40;</span><span style="color: #a52a2a;">!</span>pointer<span style="color: #6c6;">&#41;</span> <span style="color: #a52a2a;">&lt;&gt;</span> 0 <span style="color: #06c; font-weight: bold;">do</span>
            exec nodes;
          <span style="color: #06c; font-weight: bold;">done</span>
    <span style="color: #06c; font-weight: bold;">in</span>
    <span style="color: #06c; font-weight: bold;">List</span><span style="color: #a52a2a;">.</span><span style="color: #060;">iter</span> exec_node ast</pre></div></div>

<p>L&#8217;interprete basique est terminé. Il n&#8217;est pas particulièrement rapide, mais il fonctionne.</p>
<p>Voyons comment améliorer tout ca.</p>
<h3>Optimisations simples</h3>
<p>Il est possible de faire une optimisation simple, sans changer notre type opération et en conservant la structure du programme a l&#8217;identique.</p>
<p><strong>Regroupement d&#8217;opérations similaires</strong><br />
Avec une traduction simple, &#8220;+++&#8221; devient [Add(1);Add(1),Add(1)]. En les regroupant, on peut n&#8217;avoir qu&#8217;une seule instruction, Add(3). La même chose est possible pour les instructions Move.</p>

<div class="wp_syntax"><div class="code"><pre class="ocaml ocaml" style="font-family:monospace;">  <span style="color: #06c; font-weight: bold;">let</span> <span style="color: #06c; font-weight: bold;">rec</span> group <span style="color: #a52a2a;">=</span> <span style="color: #06c; font-weight: bold;">function</span>
    | Move a <span style="color: #a52a2a;">::</span> Move b <span style="color: #a52a2a;">::</span> rest <span style="color: #a52a2a;">-&gt;</span>
        <span style="color: #06c; font-weight: bold;">let</span> lst <span style="color: #a52a2a;">=</span> <span style="color: #06c; font-weight: bold;">if</span> a <span style="color: #a52a2a;">+</span> b <span style="color: #a52a2a;">&lt;&gt;</span> 0 <span style="color: #06c; font-weight: bold;">then</span> Move <span style="color: #6c6;">&#40;</span>a <span style="color: #a52a2a;">+</span> b<span style="color: #6c6;">&#41;</span> <span style="color: #a52a2a;">::</span> rest <span style="color: #06c; font-weight: bold;">else</span> rest <span style="color: #06c; font-weight: bold;">in</span>
        group lst
    | Add a <span style="color: #a52a2a;">::</span> Add b <span style="color: #a52a2a;">::</span> rest <span style="color: #a52a2a;">-&gt;</span>
        <span style="color: #06c; font-weight: bold;">let</span> lst <span style="color: #a52a2a;">=</span> <span style="color: #06c; font-weight: bold;">if</span> a <span style="color: #a52a2a;">+</span> b <span style="color: #a52a2a;">&lt;&gt;</span> 0 <span style="color: #06c; font-weight: bold;">then</span> Add <span style="color: #6c6;">&#40;</span>a <span style="color: #a52a2a;">+</span> b<span style="color: #6c6;">&#41;</span> <span style="color: #a52a2a;">::</span> rest <span style="color: #06c; font-weight: bold;">else</span> rest <span style="color: #06c; font-weight: bold;">in</span>
        group lst
    | Loop a <span style="color: #a52a2a;">::</span> rest <span style="color: #a52a2a;">-&gt;</span> <span style="color: #6c6;">&#40;</span>Loop <span style="color: #6c6;">&#40;</span>group a<span style="color: #6c6;">&#41;</span><span style="color: #6c6;">&#41;</span> <span style="color: #a52a2a;">::</span> <span style="color: #6c6;">&#40;</span>group rest<span style="color: #6c6;">&#41;</span>
    | other <span style="color: #a52a2a;">::</span> rest <span style="color: #a52a2a;">-&gt;</span> other <span style="color: #a52a2a;">::</span> <span style="color: #6c6;">&#40;</span>group rest<span style="color: #6c6;">&#41;</span>
    | <span style="color: #6c6;">&#91;</span><span style="color: #6c6;">&#93;</span> <span style="color: #a52a2a;">-&gt;</span> <span style="color: #6c6;">&#91;</span><span style="color: #6c6;">&#93;</span></pre></div></div>

<p>Et tant qu&#8217;a faire, on se débrouille pour ne pas conserver de Add(0), ce qui serait un peu dommage.</p>
<h3>Optimisations avancées</h3>
<p>On a besoin d&#8217;ajouter un type macro, et un constructeur Macro au type &#8220;operation&#8221; défini précédemment</p>

<div class="wp_syntax"><div class="code"><pre class="ocaml ocaml" style="font-family:monospace;">  <span style="color: #06c; font-weight: bold;">type</span> macro <span style="color: #a52a2a;">=</span>
    | <span style="color: #06c; font-weight: bold;">Set</span> <span style="color: #06c; font-weight: bold;">of</span> int <span style="color: #a52a2a;">*</span> int
    | AddMultToCell <span style="color: #06c; font-weight: bold;">of</span> int <span style="color: #a52a2a;">*</span> int
    | AddMultToCell2 <span style="color: #06c; font-weight: bold;">of</span> int <span style="color: #a52a2a;">*</span> int <span style="color: #a52a2a;">*</span> int
    | CopyMultToCell <span style="color: #06c; font-weight: bold;">of</span> int <span style="color: #a52a2a;">*</span> int
    | AddTo <span style="color: #06c; font-weight: bold;">of</span> int <span style="color: #a52a2a;">*</span> int
&nbsp;
  <span style="color: #06c; font-weight: bold;">type</span> operation <span style="color: #a52a2a;">=</span>
     <span style="color: #a52a2a;">...</span>
     | Macro <span style="color: #06c; font-weight: bold;">of</span> macro</pre></div></div>

<p>Voici ce qu&#8217;elles représentent :</p>
<table>
<tr>
<td>Set(n, i)</td>
<td>Ecrit la valeur n dans la cellule distante de i</td>
</tr>
<tr>
<td>AddMultToCell(n, i)</td>
<td>Ajoute (n*valeur courante) a la cellule distante de i</td>
</tr>
<tr>
<td>AddMultToCell2(n, i, j)</td>
<td>Ajoute (n*valeur courante) aux cellules distantes de i et j</td>
</tr>
<tr>
<td>AddTo(n, i)</td>
<td>Ajoute n a la cellule distante de i</td>
</tr>
</table>
<p>Les programmes BrainFuck contiennent fréquemment des séquences similaires, que nous allons remplacer par ces macros.</p>
<p><strong>Remplacement de boucles courantes par des macros</strong></p>
<p>Commençons par les boucles. Celles-ci sont :</p>
<table>
<tr>
<td>[Add -1]</td>
<td>Met la valeur de la cellule courante a 0</td>
</tr>
<tr>
<td>[Move i, Add n, Move -i, Add -1]</td>
<td>Ajoute n*(valeur courante) a la cellule distante de i</td>
</tr>
<tr>
<td>[Move i, Add n, Move j, Add n, Move -(i+j), Add -1)</td>
<td>Ajoute n*(valeur courante) aux cellules distantes de i et (i+j)</td>
</tr>
<tr>
<td>[Set (n, i), Add -1]</td>
<td>Met la cellule distante de i a la valeur n si la cellule courante est différente de 0, puis met la cellule courante a 0</td>
</tr>
</table>
<p>Passer de la boucle a sa signification sémantique, puis sa macro, n&#8217;est pas forcément évident.<br />
Si vous ne voyez pas le lien entre la boucle et sa description, ca peut valoir le coup de creuser.</p>
<p>Une fois la relation entre les opération brainfuck et ce que le programme essaye d&#8217;accomplir établie, on peut enfin les remplacer par nos macros.</p>

<div class="wp_syntax"><div class="code"><pre class="ocaml ocaml" style="font-family:monospace;">  <span style="color: #06c; font-weight: bold;">let</span> <span style="color: #06c; font-weight: bold;">rec</span> unroll ast <span style="color: #a52a2a;">=</span>
    <span style="color: #06c; font-weight: bold;">let</span> replace <span style="color: #a52a2a;">=</span> <span style="color: #06c; font-weight: bold;">function</span>
      | <span style="color: #6c6;">&#91;</span>Add <span style="color: #6c6;">&#40;</span><span style="color: #a52a2a;">-</span><span style="color: #c6c;">1</span><span style="color: #6c6;">&#41;</span><span style="color: #6c6;">&#93;</span> <span style="color: #a52a2a;">-&gt;</span> Macro <span style="color: #6c6;">&#40;</span><span style="color: #06c; font-weight: bold;">Set</span> <span style="color: #6c6;">&#40;</span>0, 0<span style="color: #6c6;">&#41;</span><span style="color: #6c6;">&#41;</span>
      | <span style="color: #6c6;">&#91;</span>Move a; Add n; Move b; Add <span style="color: #6c6;">&#40;</span><span style="color: #a52a2a;">-</span><span style="color: #c6c;">1</span><span style="color: #6c6;">&#41;</span><span style="color: #6c6;">&#93;</span>
      <span style="color: #06c; font-weight: bold;">when</span> a <span style="color: #a52a2a;">=</span> <span style="color: #a52a2a;">-</span> b <span style="color: #a52a2a;">-&gt;</span> Macro <span style="color: #6c6;">&#40;</span>AddMultToCell <span style="color: #6c6;">&#40;</span>n, a<span style="color: #6c6;">&#41;</span><span style="color: #6c6;">&#41;</span>
      | <span style="color: #6c6;">&#91;</span>Move a; Add n1; Move b; Add n2; Move c; Add <span style="color: #6c6;">&#40;</span><span style="color: #a52a2a;">-</span><span style="color: #c6c;">1</span><span style="color: #6c6;">&#41;</span><span style="color: #6c6;">&#93;</span>
      <span style="color: #06c; font-weight: bold;">when</span> a <span style="color: #a52a2a;">+</span> b <span style="color: #a52a2a;">=</span> <span style="color: #a52a2a;">-</span> c <span style="color: #a52a2a;">&amp;&amp;</span> n1 <span style="color: #a52a2a;">=</span> n2 <span style="color: #a52a2a;">-&gt;</span> Macro <span style="color: #6c6;">&#40;</span>AddMultToCell2 <span style="color: #6c6;">&#40;</span>n1, a, a <span style="color: #a52a2a;">+</span> b<span style="color: #6c6;">&#41;</span><span style="color: #6c6;">&#41;</span>
      | <span style="color: #6c6;">&#91;</span>Macro <span style="color: #6c6;">&#40;</span><span style="color: #06c; font-weight: bold;">Set</span> <span style="color: #6c6;">&#40;</span>n, i<span style="color: #6c6;">&#41;</span><span style="color: #6c6;">&#41;</span>; Add <span style="color: #6c6;">&#40;</span><span style="color: #a52a2a;">-</span><span style="color: #c6c;">1</span><span style="color: #6c6;">&#41;</span><span style="color: #6c6;">&#93;</span> <span style="color: #a52a2a;">-&gt;</span> Loop <span style="color: #6c6;">&#91;</span>Macro <span style="color: #6c6;">&#40;</span><span style="color: #06c; font-weight: bold;">Set</span> <span style="color: #6c6;">&#40;</span>n, i<span style="color: #6c6;">&#41;</span><span style="color: #6c6;">&#41;</span>; Macro <span style="color: #6c6;">&#40;</span><span style="color: #06c; font-weight: bold;">Set</span> <span style="color: #6c6;">&#40;</span>0, 0<span style="color: #6c6;">&#41;</span><span style="color: #6c6;">&#41;</span><span style="color: #6c6;">&#93;</span>
      | other <span style="color: #a52a2a;">-&gt;</span> Loop <span style="color: #6c6;">&#40;</span>unroll other<span style="color: #6c6;">&#41;</span>
    <span style="color: #06c; font-weight: bold;">in</span>
    <span style="color: #06c; font-weight: bold;">match</span> ast <span style="color: #06c; font-weight: bold;">with</span>
    | Loop ops <span style="color: #a52a2a;">::</span> rest <span style="color: #a52a2a;">-&gt;</span> replace ops <span style="color: #a52a2a;">::</span> unroll rest
    | other <span style="color: #a52a2a;">::</span> rest <span style="color: #a52a2a;">-&gt;</span> other <span style="color: #a52a2a;">::</span> <span style="color: #6c6;">&#40;</span>unroll rest<span style="color: #6c6;">&#41;</span>
    | <span style="color: #6c6;">&#91;</span><span style="color: #6c6;">&#93;</span> <span style="color: #a52a2a;">-&gt;</span> <span style="color: #6c6;">&#91;</span><span style="color: #6c6;">&#93;</span></pre></div></div>

<p><strong>Exécution directe, sans déplacement préalable</strong><br />
C&#8217;est bon pour les boucles, mais il reste d&#8217;autres séquences qu&#8217;on peut réduire.</p>
<p>On retrouve souvent la séquence [Move i, Action, Move -i]. Si on peut le remplacer par une action distante, on gagne deux déplacements.</p>

<div class="wp_syntax"><div class="code"><pre class="ocaml ocaml" style="font-family:monospace;">  <span style="color: #06c; font-weight: bold;">let</span> in_place ast <span style="color: #a52a2a;">=</span>
    <span style="color: #06c; font-weight: bold;">let</span> <span style="color: #06c; font-weight: bold;">rec</span> loop <span style="color: #a52a2a;">=</span> <span style="color: #06c; font-weight: bold;">function</span>
      | Move i <span style="color: #a52a2a;">::</span> Add n <span style="color: #a52a2a;">::</span> Move j <span style="color: #a52a2a;">::</span> rest
        <span style="color: #06c; font-weight: bold;">when</span> i <span style="color: #a52a2a;">=</span> <span style="color: #a52a2a;">-</span> j <span style="color: #a52a2a;">-&gt;</span> Macro <span style="color: #6c6;">&#40;</span>AddTo <span style="color: #6c6;">&#40;</span>n, i<span style="color: #6c6;">&#41;</span><span style="color: #6c6;">&#41;</span> <span style="color: #a52a2a;">::</span> loop rest
      | Move i <span style="color: #a52a2a;">::</span> Add n <span style="color: #a52a2a;">::</span> Move j <span style="color: #a52a2a;">::</span> rest <span style="color: #a52a2a;">-&gt;</span> 
        Macro <span style="color: #6c6;">&#40;</span>AddTo <span style="color: #6c6;">&#40;</span>n, i<span style="color: #6c6;">&#41;</span><span style="color: #6c6;">&#41;</span> <span style="color: #a52a2a;">::</span> loop <span style="color: #6c6;">&#40;</span>Move <span style="color: #6c6;">&#40;</span>i<span style="color: #a52a2a;">+</span>j<span style="color: #6c6;">&#41;</span> <span style="color: #a52a2a;">::</span> rest<span style="color: #6c6;">&#41;</span>
      | Move i <span style="color: #a52a2a;">::</span> Macro <span style="color: #6c6;">&#40;</span><span style="color: #06c; font-weight: bold;">Set</span> <span style="color: #6c6;">&#40;</span>n, j<span style="color: #6c6;">&#41;</span><span style="color: #6c6;">&#41;</span> <span style="color: #a52a2a;">::</span> Move k <span style="color: #a52a2a;">::</span> rest 
        <span style="color: #06c; font-weight: bold;">when</span> i <span style="color: #a52a2a;">=</span> <span style="color: #a52a2a;">-</span>k <span style="color: #a52a2a;">-&gt;</span> Macro <span style="color: #6c6;">&#40;</span><span style="color: #06c; font-weight: bold;">Set</span> <span style="color: #6c6;">&#40;</span>n, i<span style="color: #6c6;">&#41;</span><span style="color: #6c6;">&#41;</span> <span style="color: #a52a2a;">::</span> loop rest
      | Loop ops <span style="color: #a52a2a;">::</span> rest <span style="color: #a52a2a;">-&gt;</span> Loop <span style="color: #6c6;">&#40;</span>loop ops<span style="color: #6c6;">&#41;</span> <span style="color: #a52a2a;">::</span> loop rest
      | other <span style="color: #a52a2a;">::</span> rest <span style="color: #a52a2a;">-&gt;</span> other <span style="color: #a52a2a;">::</span> loop rest
      | <span style="color: #6c6;">&#91;</span><span style="color: #6c6;">&#93;</span> <span style="color: #a52a2a;">-&gt;</span> <span style="color: #6c6;">&#91;</span><span style="color: #6c6;">&#93;</span>
    <span style="color: #06c; font-weight: bold;">in</span> loop ast</pre></div></div>

<p>Et voila le travail.</p>
<p><strong>Retour sur les regroupements</strong><br />
On avait déjà regroupé les Add et Move (c&#8217;était notre première optimisation).<br />
Il est aussi possible de regrouper les opérations impliquant nos macros, dans une deuxième passe.</p>

<div class="wp_syntax"><div class="code"><pre class="ocaml ocaml" style="font-family:monospace;">  <span style="color: #06c; font-weight: bold;">let</span> <span style="color: #06c; font-weight: bold;">rec</span> group <span style="color: #a52a2a;">=</span> <span style="color: #06c; font-weight: bold;">function</span>
    <span style="color: #a52a2a;">...</span>
    | Add a <span style="color: #a52a2a;">::</span> Macro <span style="color: #6c6;">&#40;</span><span style="color: #06c; font-weight: bold;">Set</span> <span style="color: #6c6;">&#40;</span>n, 0<span style="color: #6c6;">&#41;</span><span style="color: #6c6;">&#41;</span> <span style="color: #a52a2a;">::</span> rest <span style="color: #a52a2a;">-&gt;</span> group <span style="color: #6c6;">&#40;</span>Macro <span style="color: #6c6;">&#40;</span><span style="color: #06c; font-weight: bold;">Set</span> <span style="color: #6c6;">&#40;</span>n, 0<span style="color: #6c6;">&#41;</span><span style="color: #6c6;">&#41;</span> <span style="color: #a52a2a;">::</span> rest<span style="color: #6c6;">&#41;</span>
    | Macro <span style="color: #6c6;">&#40;</span><span style="color: #06c; font-weight: bold;">Set</span> <span style="color: #6c6;">&#40;</span>_, i<span style="color: #6c6;">&#41;</span><span style="color: #6c6;">&#41;</span> <span style="color: #a52a2a;">::</span> Macro <span style="color: #6c6;">&#40;</span><span style="color: #06c; font-weight: bold;">Set</span> <span style="color: #6c6;">&#40;</span>n, j<span style="color: #6c6;">&#41;</span><span style="color: #6c6;">&#41;</span> <span style="color: #a52a2a;">::</span> rest 
      <span style="color: #06c; font-weight: bold;">when</span> i <span style="color: #a52a2a;">=</span> j <span style="color: #a52a2a;">-&gt;</span> group <span style="color: #6c6;">&#40;</span>Macro <span style="color: #6c6;">&#40;</span><span style="color: #06c; font-weight: bold;">Set</span> <span style="color: #6c6;">&#40;</span>n, j<span style="color: #6c6;">&#41;</span><span style="color: #6c6;">&#41;</span> <span style="color: #a52a2a;">::</span> rest<span style="color: #6c6;">&#41;</span>
    | Macro <span style="color: #6c6;">&#40;</span><span style="color: #06c; font-weight: bold;">Set</span> <span style="color: #6c6;">&#40;</span>n, 0<span style="color: #6c6;">&#41;</span><span style="color: #6c6;">&#41;</span> <span style="color: #a52a2a;">::</span> Add a <span style="color: #a52a2a;">::</span> rest <span style="color: #a52a2a;">-&gt;</span> group <span style="color: #6c6;">&#40;</span>Macro <span style="color: #6c6;">&#40;</span><span style="color: #06c; font-weight: bold;">Set</span> <span style="color: #6c6;">&#40;</span>n<span style="color: #a52a2a;">+</span>a, 0<span style="color: #6c6;">&#41;</span><span style="color: #6c6;">&#41;</span> <span style="color: #a52a2a;">::</span> rest<span style="color: #6c6;">&#41;</span>
    <span style="color: #a52a2a;">...</span></pre></div></div>

<p>Et notre optimisation va s&#8217;arreter ici. Il reste possible de faire d&#8217;autres macros pour d&#8217;autres séquences communes, mais cela n&#8217;apporterait pas grand chose d&#8217;un point de vue pédagogique.</p>
<h3>Le résultat</h3>
<p>Le <a href="https://bitbucket.org/vfiack/ocaml-toys/src/07f3f3c1c9fa/brainfuck/brainfuck.ml">code complet</a> de l&#8217;interpreteur.<br />
Le programme benchmark, qui calcule des nombres premiers : <a href="https://bitbucket.org/vfiack/ocaml-toys/src/07f3f3c1c9fa/brainfuck/prime.bf">prime.bf</a></p>
<p><strong>Sans optimisation</strong></p>
<pre>$ time (echo 99 | ./brainfuck.native prime.bf)
Primes up to: 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 

real	0m1.871s
user	0m1.868s
sys	0m0.000s
</pre>
<p><strong>Avec optimisations</strong></p>
<pre>
$ time (echo 99 | ./brainfuck.native -optimize prime.bf)
Primes up to: 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 

real	0m0.064s
user	0m0.056s
sys	0m0.004s
</pre>
<p>En gros, ca va 30x plus vite. Si seulement tout pouvait s&#8217;optimiser aussi facilement !</p>
<h3>A vous de jouer</h3>
<p>Grace au projet <a href="http://ocsigen.org/js_of_ocaml/">js_of_ocaml</a>, j&#8217;ai pu porter le compilateur en javascript. Il est <a href="http://vfiack.fr/blog-addons/brainfuck.php">utilisable ici</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.vfiack.fr/120-un-interpreteur-optimiseur-de-brainfuck-en-ocaml/feed/</wfw:commentRss>
		</item>
		<item>
		<title>La méthode Monte-Carlo appliquée au go, pour les nuls</title>
		<link>http://blog.vfiack.fr/93-la-methode-monte-carlo-appliquee-au-go-pour-les-nuls/</link>
		<comments>http://blog.vfiack.fr/93-la-methode-monte-carlo-appliquee-au-go-pour-les-nuls/#comments</comments>
		<pubDate>Fri, 26 Mar 2010 08:49:22 +0000</pubDate>
		<dc:creator>vfiack</dc:creator>
		
		<category><![CDATA[Développement]]></category>

		<category><![CDATA[Jeu de go]]></category>

		<category><![CDATA[Monte Carlo]]></category>

		<guid isPermaLink="false">http://blog.vfiack.fr/?p=93</guid>
		<description><![CDATA[J&#8217;avais découvert le jeu de go en 2004 suite a un article sur les difficultés d&#8217;implémentation d&#8217;un programme efficace.
J&#8217;ai appris les règles a ce moment la, et bricolé un goban en tissus, puis tout laissé tombé en moins d&#8217;un mois faute de partenaires.
J&#8217;ai repris cet été, et je passe mon temps a jouer sur Internet [...]]]></description>
			<content:encoded><![CDATA[<p>J&#8217;avais découvert le jeu de go en 2004 suite a un article sur les difficultés d&#8217;implémentation d&#8217;un programme efficace.</p>
<p>J&#8217;ai appris les règles a ce moment la, et bricolé un goban en tissus, puis tout laissé tombé en moins d&#8217;un mois faute de partenaires.</p>
<p>J&#8217;ai repris cet été, et je passe mon temps a jouer sur Internet (KGS, IGS et wBaduk de temps en temps). Je pense que je suis bien accroc ce coup-ci.<br />
Et pour boucler la boucle, je viens d&#8217;écrire un petit programme afin de comprendre comment ceux-ci peuvent fonctionner, a partir d&#8217;un algorithme de référence (je n&#8217;ai rien inventé).</p>
<p>Je vais essayer de le décrire ici. </p>
<h2>Le programme de référence</h2>
<p>Le <a href="http://cgos.boardspace.net/public/javabot.zip">programme de référence (jrefgo)</a> utilise la méthode Monte-Carlo avec une évaluation en All Moves As First (AMAF). </p>
<p>Et si vous avez compris cette phrase, vous n&#8217;avez pas besoin de lire cette note, puisque c&#8217;est précisément ce que je vais tenter d&#8217;expliquer.</p>
<p>Ce programme a l&#8217;avantage d&#8217;être concis : une classe pour <a href="http://www.lysator.liu.se/~gunnar/gtp/">GTP (Go Text Protocol)</a>, un lanceur, et une classe principale qui gère tout le reste.</p>
<p>Malheureusement, il n&#8217;est pas aussi clair qu&#8217;il le pourrait, les variables ont des noms abscons, il y a des manipulations de bits qui ne sont pas forcément nécessaires, et beaucoup d&#8217;attributs utilisés comme des variables globales. Il reste néanmoins une bonne base, et je me suis plus ou moins contenté de le réarranger a ma sauce, sans en changer le fonctionnement.</p>
<p>Attention: je suis un développeur, pas un statisticien, il est donc possible que j&#8217;ai introduit des erreurs ou mal compris un point. N&#8217;hésitez pas a me corriger si vous voyez une bourde.</p>
<h2>Pourquoi le jeu de go est difficile pour un ordinateur</h2>
<p>Pour la plupart des jeux de stratégies de ce type, une intelligence artificielle est composée de deux éléments principaux :</p>
<ul>
<li>un arbre des coups possibles pour chaque joueur</li>
<li>une fonction d&#8217;évaluation d&#8217;une position donnée</li>
</ul>
<p>A partir de la, on peut évaluer les positions obtenues après X coups, et prendre le coup qui amène a la meilleure de ces positions.</p>
<p>Cette méthode n&#8217;est pas applicable au go pour deux raisons : </p>
<ul>
<li>le nombre de coups possibles est gigantesque, il n&#8217;est pas possible de générer un arbre d&#8217;une profondeur acceptable</li>
<li>il est très dur d&#8217;évaluer une position (Ce territoire est-il définitif ? Ce groupe est-il vraiment vivant ? Combien vaut cette influence ? Et la pierre en bas, elle est morte, mais a-t-elle encore du potentiel ?)</li>
</ul>
<p>Il a donc fallu trouver un autre angle d&#8217;approche.</p>
<h2>La méthode Monte-Carlo</h2>
<p>L&#8217;idée est assez simple, et je suis moi-même étonné de voir qu&#8217;elle fonctionne aussi bien :<br />
puisqu&#8217;on n&#8217;est capable d&#8217;évaluer une position qu&#8217;en fin de partie, il suffit de la finir ! </p>
<p>Ben oui, mais comment ? En jouant des coups au hasard. C&#8217;est ce qu&#8217;on appelle un &#8220;playout&#8221;. Ça fait une fin de partie absolument non réaliste, et peu fiable.<br />
Mais si on joue 10 000 playouts ou plus, on commence a avoir des résultats intéressants. C&#8217;est une approche probabiliste. </p>
<p>En divisant le nombre de victoires par le nombre de playouts, on obtient une probabilité de victoire, le winrate. Le score ne compte pas vraiment, gagner de 0.5 ou de 30 points n&#8217;a pas d&#8217;importance. Si une position a un winrate > 0.5, la position est favorable, et inversement. </p>
<p>Corolaire : le coup qui amène a une position ayant le meilleur winrate est probablement le meilleur coup.</p>
<h2>All Moves As First</h2>
<p>Reste a savoir comment on mémorise le winrate pour chaque coup ou position. L&#8217;approche AMAF, c&#8217;est de ne pas tenir compte de l&#8217;ordre des coups, et juger toutes les pierres jouées entre la position initiale et la position finale. Par exemple, si 50 coups sont joués entre la position pour laquelle on veut trouver un coup, et la fin d&#8217;un playout, on comptabilise une victoire pour chacun des coups qui ont été joués.</p>
<p>L&#8217;avantage de cette méthode est le stockage du résultat : un tableau de la taille d&#8217;un goban suffit, avec un score pour chaque case. On obtient le meilleur coup après<br />
simulation de toutes les fins de parties en parcourant ce tableau, et en conservant le coup avec le meilleur winrate.</p>
<p>L&#8217;inconvénient majeur de cette méthode est que le coup ayant le plus de chance de marcher contre un adversaire jouant au hasard n&#8217;est pas forcément le meilleur coup.<br />
Un humain ne rate pas un simple shicho et ne se met pas en auto-atari en espérant que son adversaire l&#8217;ignore&#8230;</p>
<h2>Implémentation</h2>
<p>Il nous faut certaines fonction de base que je ne décrirais pas en détail, mais dont vous pouvez voir le source :</p>
<ul>
<li>une structure contenant une position (<a href="http://bitbucket.org/vfiack/weiqibot/src/c710f149ec48/src/main/java/fr/vfiack/go/Board.java#cl-27">classe Board</a>)</li>
<li>un moyen d&#8217;avoir le score d&#8217;une position finale (<a href="http://bitbucket.org/vfiack/weiqibot/src/c710f149ec48/src/main/java/fr/vfiack/go/Scorer.java#cl-3">classe Scorer</a>)</li>
<li>un moyen de vérifier la validité d&#8217;un coup et de le jouer (<a href="http://bitbucket.org/vfiack/weiqibot/src/c710f149ec48/src/main/java/fr/vfiack/go/MoveManager.java#cl-4">classe MoveManager</a>)</li>
</ul>
<p>Une fois qu&#8217;on a ces éléments, on peut rentrer dans le cœur du problème : la génération des playouts, les statistiques, et enfin la sélection du coup a jouer.</p>
<p><strong>Génération d&#8217;un playout</strong><br />
CODE: <a href="http://bitbucket.org/vfiack/weiqibot/src/c710f149ec48/src/main/java/fr/vfiack/go/generators/McAmafGenerator.java#cl-134">McAmafGenerator.playout</a></p>
<ol>
<li>on récupère la liste des intersections libres</li>
<li>tant qu&#8217;il reste des intersections libres, on en sélectionne une au hasard qu&#8217;on déplace pour ne pas la resélectionner plus tard</li>
<li>si l&#8217;intersection est valide, on la joue pour le joueur courant, sinon on recommence la sélection avec un autre coup</li>
<li>si le coup capture des pierres adverses, on récupère a nouveau la liste des intersections libres et on recommence au début, avec la position actuelle</li>
<li>lorsqu&#8217;il ne reste plus de coup valide, on passe. Après 2 passes consécutives, la simulation est terminée</li>
<li>on regarde qui gagne la partie dans la position finale, et on sauve les statistiques</li>
</ol>
<p><strong>Sauvegarde des statistiques après chaque playout</strong><br />
CODE: <a href="http://bitbucket.org/vfiack/weiqibot/src/c710f149ec48/src/main/java/fr/vfiack/go/generators/McAmafGenerator.java#cl-226">McAmafGenerator.trackStatistics</a></p>
<p>Pour chaque coup joué dans le playout par le joueur pour lequel on veut trouver un coup :</p>
<ol>
<li>vérifier qu&#8217;il n&#8217;a pas déjà été joué avant depuis la position initiale, par aucun des deux joueurs</li>
<li>s&#8217;il n&#8217;a pas encore été joué, ajoute 1 ou -1 au score du coup selon le résultat final de la partie, et incrémente le nombre de simulations contenant ce coup.</li>
</ol>
<p>L&#8217;ordre des coups n&#8217;a pas d&#8217;importance, mais on ne compte chaque coup qu&#8217;une seule fois au maximum par playout.</p>
<p><strong>Sélection du coup a jouer</strong><br />
CODE: <a href="http://bitbucket.org/vfiack/weiqibot/src/c710f149ec48/src/main/java/fr/vfiack/go/generators/McAmafGenerator.java#cl-55">McAmafGenerator.generateMove</a></p>
<ol>
<li>on remet les statistiques a zéro pour ne pas être influencé par les résultats des évaluations précédentes</li>
<li>on joue plein de playouts aléatoires</li>
<li>on récupère la liste de toutes les intersections du goban, qu&#8217;on mélange pour ne pas avoir toujours le même ordre de sélection en cas de winrates identiques</li>
<li>on récupère le winrate pour chaque intersection, si elle correspond un coup légal qui ne remplit pas un de ses propres yeux. S&#8217;il est meilleur que celui du coup actuellement sélectionné, on sélectionne le coup correspondant</li>
<li>s&#8217;il n&#8217;y a aucun coup légal restant, on passe</li>
<li>si le winrate de la position de départ est vraiment trop faible, on abandonne.</li>
</ol>
<h2>Pour aller plus loin</h2>
<p>Les programmes de ce types évoluent généralement de deux façons :</p>
<ul>
<li>en conservant l&#8217;ordre des coups dans un arbre (ex: UCT)</li>
<li>en ne faisant pas des playouts totalement aléatoires, mais plus plausibles (heavy playouts), en utilisant des heuristiques basées sur de la reconnaissance de forme.</li>
</ul>
<h2>Liens sur le sujet</h2>
<p>Sur Wikipedia :<br />
<a href="http://fr.wikipedia.org/wiki/Jeu_de_go_%28informatique%29">http://fr.wikipedia.org/wiki/Jeu_de_go_(informatique)</a></p>
<p>Le programme de référence :<br />
<a href="http://cgos.boardspace.net/public/javabot.zip">http://cgos.boardspace.net/public/javabot.zip</a></p>
<p>Un port dans le langage &#8220;Google Go&#8221; :<br />
<a href="http://github.com/skybrian/Gongo">http://github.com/skybrian/Gongo</a></p>
<p>Archives de la liste Computer-Go :<br />
<a href="http://groups.google.com/group/computer-go-archive">http://groups.google.com/group/computer-go-archive</a></p>
<p>Mon source :<br />
<a href="http://bitbucket.org/vfiack/weiqibot/">http://bitbucket.org/vfiack/weiqibot/</a></p>
<p>Pages sur Sensei&#8217;s Library :<br />
<a href="http://senseis.xmp.net/?ComputerGoAlgorithms">http://senseis.xmp.net/?ComputerGoAlgorithms</a><br />
<a href="http://senseis.xmp.net/?MonteCarlo">http://senseis.xmp.net/?MonteCarlo</a><br />
<a href="http://senseis.xmp.net/?UCT">http://senseis.xmp.net/?UCT</a></p>
<p>Un PDF sur les valeurs intéressantes :<br />
<a href="http://www.fun.ac.jp/~kishi/pdf_file/AAAI06YoshimotoH.pdf">http://www.fun.ac.jp/~kishi/pdf_file/AAAI06YoshimotoH.pdf</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.vfiack.fr/93-la-methode-monte-carlo-appliquee-au-go-pour-les-nuls/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Polska after Sven Donat</title>
		<link>http://blog.vfiack.fr/82-polska-after-sven-donat/</link>
		<comments>http://blog.vfiack.fr/82-polska-after-sven-donat/#comments</comments>
		<pubDate>Sat, 13 Jun 2009 07:08:04 +0000</pubDate>
		<dc:creator>vfiack</dc:creator>
		
		<category><![CDATA[coup de coeur]]></category>

		<category><![CDATA[nyckelharpa]]></category>

		<guid isPermaLink="false">http://blog.vfiack.fr/?p=82</guid>
		<description><![CDATA[De temps en temps, on tombe sur des perles. Ici, il s&#8217;agit d&#8217;une polka jouée par Magnus Holmstr&#246;m.

Je connaissais déjà la nyckelharpa, cet instrument suédois dont le spécialiste régionnal est Jean-Claude Condi, mais je ne l&#8217;avais jamais entendue avec un son si propre. Par moments, on a du mal a croire qu&#8217;il n&#8217;y a qu&#8217;un [...]]]></description>
			<content:encoded><![CDATA[<p>De temps en temps, on tombe sur des perles. Ici, il s&#8217;agit d&#8217;une polka jouée par <a href="http://www.magnusholmstrom.com/">Magnus Holmstr&ouml;m</a>.</p>
<p><object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/D93OD5IYDx4&#038;hl=fr&#038;fs=1&#038;rel=0"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/D93OD5IYDx4&#038;hl=fr&#038;fs=1&#038;rel=0" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"></embed></object></p>
<p>Je connaissais déjà la <a href="http://fr.wikipedia.org/wiki/Nyckelharpa">nyckelharpa</a>, cet instrument suédois dont le spécialiste régionnal est <a href="http://www.nyckelharpa-condi.com/">Jean-Claude Condi</a>, mais je ne l&#8217;avais jamais entendue avec un son si propre. Par moments, on a du mal a croire qu&#8217;il n&#8217;y a qu&#8217;un seul musicien sur scène.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.vfiack.fr/82-polska-after-sven-donat/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Protégé&#160;: How not to design a license server</title>
		<link>http://blog.vfiack.fr/71-how-not-to-design-a-license-serve/</link>
		<comments>http://blog.vfiack.fr/71-how-not-to-design-a-license-serve/#comments</comments>
		<pubDate>Thu, 19 Mar 2009 07:31:44 +0000</pubDate>
		<dc:creator>vfiack</dc:creator>
		
		<category><![CDATA[Développement]]></category>

		<category><![CDATA[citrix]]></category>

		<guid isPermaLink="false">http://blog.vfiack.fr/?p=71</guid>
		<description><![CDATA[Il n&#8217;y pas d&#8217;extrait, car cet article est protégé.]]></description>
			<content:encoded><![CDATA[<form action="http://blog.vfiack.fr/wp-pass.php" method="post">
<p>Cet article est protégé par mot de passe. Pour le lire, veuillez saisir votre mot de passe ci-dessous&nbsp;:</p>
<p><label for="pwbox-71">Mot de passe&nbsp;:<br />
<input name="post_password" id="pwbox-71" type="password" size="20" /></label><br />
<input type="submit" name="Submit" value="Envoyer" /></p></form>
]]></content:encoded>
			<wfw:commentRss>http://blog.vfiack.fr/71-how-not-to-design-a-license-serve/feed/</wfw:commentRss>
		</item>
		<item>
		<title>La note mystère</title>
		<link>http://blog.vfiack.fr/62-la-note-mystere/</link>
		<comments>http://blog.vfiack.fr/62-la-note-mystere/#comments</comments>
		<pubDate>Thu, 05 Feb 2009 12:25:52 +0000</pubDate>
		<dc:creator>vfiack</dc:creator>
		
		<category><![CDATA[Musique]]></category>

		<guid isPermaLink="false">http://blog.vfiack.fr/?p=62</guid>
		<description><![CDATA[En ce moment, je travaille la Sarabande de la première suite de Bach pour violoncelle seul. 
C&#8217;est une œuvre pour laquelle nous n&#8217;avons pas de manuscrit autographe, mais uniquement des manuscrits de copistes (un par Anna Magdalena, sa seconde épouse, et deux autres que je n&#8217;ai jamais vu). Ces manuscrits ne sont pas forcément d&#8217;accord [...]]]></description>
			<content:encoded><![CDATA[<p>En ce moment, je travaille la Sarabande de la première <a href="http://fr.wikipedia.org/wiki/Suites_pour_violoncelle_seul_(Bach)">suite de Bach pour violoncelle seul</a>. </p>
<p>C&#8217;est une œuvre pour laquelle nous n&#8217;avons pas de manuscrit autographe, mais uniquement des manuscrits de copistes (<a href="http://imslp.org/wiki/Suites_for_Violoncello_Solo%2C_BWV_1007-1012_(Bach%2C_Johann_Sebastian)#Manuscripts">un par Anna Magdalena</a>, sa seconde épouse, et deux autres que je n&#8217;ai jamais vu). Ces manuscrits ne sont pas forcément d&#8217;accord entre eux, que ce soit sur les liaisons ou même sur les notes, et on arrive donc a des éditions modernes qui comportent des différence.</p>
<p>Pour ce qui me concerne, voici l&#8217;extrait du manuscrit d&#8217;Anna Magdalena:<br />
<img src="http://blog.vfiack.fr/wp-content/uploads/2009/02/sarabande.png" alt="Début de la sarabande de la première suite" title="Début de la sarabande de la première suite"  /></p>
<p>La dernière double croche de la ligne n&#8217;est pas très lisible. <a href="http://icking-music-archive.org/scores/bach/cello_suites/vc100712.pdf">L&#8217;édition que j&#8217;utilise</a> m&#8217;indique un la, <a href="http://www.mutopiaproject.org/cgibin/make-table.cgi?collection=bachcello&#038;preview=1">celle de mutopia</a> indique un sol.</p>
<p>Laquelle détient la vérité ?</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.vfiack.fr/62-la-note-mystere/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Le même avec ANTLR</title>
		<link>http://blog.vfiack.fr/50-le-meme-avec-antlr/</link>
		<comments>http://blog.vfiack.fr/50-le-meme-avec-antlr/#comments</comments>
		<pubDate>Fri, 16 Jan 2009 08:33:49 +0000</pubDate>
		<dc:creator>vfiack</dc:creator>
		
		<category><![CDATA[Développement]]></category>

		<guid isPermaLink="false">http://blog.vfiack.fr/?p=50</guid>
		<description><![CDATA[Juste pour la forme, j&#8217;avais parsé mon document avec jparsec, voici la même chose, mais ce coup-ci avec ANTLR.
ANTLR, c&#8217;est beaucoup plus classique : une grammaire dans un langage particulier, et on génère le code du parser a partir de cette grammaire. Son gros point fort, c&#8217;est ANTLRWorks, un chouette outil d&#8217;édition et surtout de [...]]]></description>
			<content:encoded><![CDATA[<p>Juste pour la forme, j&#8217;avais <a href="http://blog.vfiack.fr/7-un-parser-tres-basique-avec-jparser/">parsé mon document avec jparsec</a>, voici la même chose, mais ce coup-ci avec <a href="http://www.antlr.org/">ANTLR</a>.</p>
<p>ANTLR, c&#8217;est beaucoup plus classique : une grammaire dans un langage particulier, et on génère le code du parser a partir de cette grammaire. Son gros point fort, c&#8217;est <a href="http://www.antlr.org/works/index.html">ANTLRWorks</a>, un chouette outil d&#8217;édition et surtout de débug de grammaires. C&#8217;est encore perfectible, surtout au niveau de l&#8217;ergonomie, mais ça remplit son office.</p>
<p>Le document à parser :</p>

<div class="wp_syntax"><div class="code"><pre class="json" style="font-family:monospace;">{abc|123|tralala}
{cde||youpie|tsoin tsoin|}</pre></div></div>

<p>Chaque ligne est une étiquette, le nombre de champs est variable, et les champs vides sont autorisés. On veut récupérer un arbre :</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
</pre></td><td class="code"><pre class="antlr" style="font-family:monospace;">grammar Etiquettes;
&nbsp;
options { output=AST; }
tokens { ETIQUETTE; FIELD; }</pre></td></tr></table></div>

<p>Par convention, les tokens arbitraires sont tout en majuscules, les règles du lexer commencent par une majuscule, et les règles du parser par une minuscule. La règle principale s&#8217;appelle expr, et décrit l&#8217;ensemble du document.</p>
<p>La liste des tokens que le lexer doit repérer est assez claire :</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>5
6
7
8
9
</pre></td><td class="code"><pre class="antlr" style="font-family:monospace;">Opening	:	'{';
Closing	:	'}';
Separator:	'|';
EndOfLine :	'n';
Text	:	~(Separator | Opening | Closing | EndOfLine)+;</pre></td></tr></table></div>

<p>Le texte, c&#8217;est tout ce qui n&#8217;est pas autre chose. J&#8217;imagine qu&#8217;il doit y avoir un moyen plus simple de le spécifier, mais je ne l&#8217;ai pas trouvé.</p>
<p>A partir de cet ensemble de tokens, on peut enfin construire notre document :</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>10
11
12
</pre></td><td class="code"><pre class="antlr" style="font-family:monospace;">expr	:	etiquette+;
etiquette:	Opening field (Separator field)* Closing EndOfLine? -&gt; ^(ETIQUETTE field+);
field	:	Text? -&gt; ^(FIELD Text?);</pre></td></tr></table></div>

<p>On veut toujours parser une ou plusieurs étiquettes.<br />
Une étiquette est construite à partir d&#8217;une ouverture, puis d&#8217;un ensemble de champs, d&#8217;une fermeture, et optionnellement d&#8217;une fin de ligne. Ce qui suit les flèches (->), c&#8217;est ce qu&#8217;on veut remonter dans l&#8217;arbre.</p>
<p>Avec tout ça, on peut enfin lancer le débugger d&#8217;ANTLRWorks sur notre petit document, et on obtient ceci :<br />
<img src="http://blog.vfiack.fr/wp-content/uploads/2009/01/antlr-etiquettes.png" alt="Arbre généré" title="Arbre généré" width="630" height="176" class="aligncenter size-full wp-image-53" /></p>
<p>Il reste encore a récupérer l&#8217;arbre coté Java, mais <a href="http://www.antlr.org/wiki/display/ANTLR3/Interfacing+AST+with+Java">c&#8217;est assez simple</a>.</p>
<p>Si je voulais comparer avec ma version précédente utilisant jparsec, ça prends plus de code, ça demande une génération de code + parcours manuel de l&#8217;arbre, mais c&#8217;est plus clair. Je n&#8217;ai pas comparé les performances.</p>
<p>Je pense que pour des documents plus complexe, je préfèrerais utiliser ANTLR, c&#8217;est plus simple a tester.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.vfiack.fr/50-le-meme-avec-antlr/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Variations sur un thème</title>
		<link>http://blog.vfiack.fr/17-variations-sur-un-theme/</link>
		<comments>http://blog.vfiack.fr/17-variations-sur-un-theme/#comments</comments>
		<pubDate>Tue, 06 Jan 2009 14:46:02 +0000</pubDate>
		<dc:creator>vfiack</dc:creator>
		
		<category><![CDATA[Développement]]></category>

		<guid isPermaLink="false">http://blog.vfiack.fr/?p=17</guid>
		<description><![CDATA[De temps en temps, j&#8217;essaye d&#8217;écrire Monarques sous forme de jeu vidéo. Je n&#8217;en finirai sans doute jamais aucune version, mais ça m&#8217;occupe, et me permet de simplifier le jeu papier.
Un des points que j&#8217;aime bien, c&#8217;est la définition d&#8217;un château. Dans Monarques, c&#8217;est tout simplement une série de cases adjacentes, qui peuvent recruter des [...]]]></description>
			<content:encoded><![CDATA[<p>De temps en temps, j&#8217;essaye d&#8217;écrire <a href="http://monarques.vfiack.fr">Monarques</a> sous forme de jeu vidéo. Je n&#8217;en finirai sans doute jamais aucune version, mais ça m&#8217;occupe, et me permet de simplifier le jeu papier.</p>
<p>Un des points que j&#8217;aime bien, c&#8217;est la définition d&#8217;un château. Dans Monarques, c&#8217;est tout simplement une série de cases adjacentes, qui peuvent recruter des unités. Il faut pouvoir vérifier si deux cases font partie d&#8217;un même château, afin d&#8217;éviter que deux armées débutent au même endroit.</p>
<p>Les variations qui suivent sont bâties sur un principe identique :</p>
<ul>
<li>on part d&#8217;une case (x, y)</li>
<li>si c&#8217;est une case d&#8217;un château, et que le château en cours de construction ne la contient pas déjà, on l&#8217;ajoute</li>
<li>et on récurse sur les cases voisines</li>
</ul>
<p><strong>Variation impérative / objet</strong><br />
La première que j&#8217;ai écrite. Très simple, mais un peu laid, au niveau de la récursion sur les cases adjacentes. Peut mieux faire.</p>

<div class="wp_syntax"><div class="code"><pre class="java java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> Castle
<span style="color: #009900;">&#123;</span>
	<span style="color: #000000; font-weight: bold;">private</span> <span style="color: #003399;">Map</span> map;
	<span style="color: #000000; font-weight: bold;">private</span> <span style="color: #003399;">Collection</span> elems;
&nbsp;
	<span style="color: #000000; font-weight: bold;">protected</span> Castle<span style="color: #009900;">&#40;</span><span style="color: #003399;">Map</span> map, <span style="color: #000066; font-weight: bold;">int</span> x, <span style="color: #000066; font-weight: bold;">int</span> y<span style="color: #009900;">&#41;</span>
	<span style="color: #009900;">&#123;</span>
		<span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">map</span> <span style="color: #339933;">=</span> map;
		<span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">elems</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">ArrayList</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
&nbsp;
		MapElement elem <span style="color: #339933;">=</span> map.<span style="color: #006633;">getElementAt</span><span style="color: #009900;">&#40;</span>x, y<span style="color: #009900;">&#41;</span>;
		buildCastle<span style="color: #009900;">&#40;</span>elem<span style="color: #009900;">&#41;</span>;
	<span style="color: #009900;">&#125;</span>
&nbsp;
	<span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000066; font-weight: bold;">void</span> buildCastle<span style="color: #009900;">&#40;</span>MapElement elem<span style="color: #009900;">&#41;</span>
	<span style="color: #009900;">&#123;</span>
		<span style="color: #000000; font-weight: bold;">if</span><span style="color: #009900;">&#40;</span>elem <span style="color: #339933;">==</span> <span style="color: #000066; font-weight: bold;">null</span> || <span style="color: #339933;">!</span>elem.<span style="color: #006633;">canRecruitUnits</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> || elems.<span style="color: #006633;">contains</span><span style="color: #009900;">&#40;</span>elem<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
			 <span style="color: #000000; font-weight: bold;">return</span>;
&nbsp;
		elems.<span style="color: #006633;">add</span><span style="color: #009900;">&#40;</span>elem<span style="color: #009900;">&#41;</span>;
&nbsp;
		Coordinates coord <span style="color: #339933;">=</span> elem.<span style="color: #006633;">getCoordinates</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
		buildCastle<span style="color: #009900;">&#40;</span>map.<span style="color: #006633;">getElementAt</span><span style="color: #009900;">&#40;</span>coord.<span style="color: #006633;">getX</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-</span><span style="color: #cc66cc;">1</span>, coord.<span style="color: #006633;">getY</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>;
		buildCastle<span style="color: #009900;">&#40;</span>map.<span style="color: #006633;">getElementAt</span><span style="color: #009900;">&#40;</span>coord.<span style="color: #006633;">getX</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-</span><span style="color: #cc66cc;">1</span>, coord.<span style="color: #006633;">getY</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>;
		buildCastle<span style="color: #009900;">&#40;</span>map.<span style="color: #006633;">getElementAt</span><span style="color: #009900;">&#40;</span>coord.<span style="color: #006633;">getX</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-</span><span style="color: #cc66cc;">1</span>, coord.<span style="color: #006633;">getY</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">+</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>;
		buildCastle<span style="color: #009900;">&#40;</span>map.<span style="color: #006633;">getElementAt</span><span style="color: #009900;">&#40;</span>coord.<span style="color: #006633;">getX</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>, coord.<span style="color: #006633;">getY</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>;
		buildCastle<span style="color: #009900;">&#40;</span>map.<span style="color: #006633;">getElementAt</span><span style="color: #009900;">&#40;</span>coord.<span style="color: #006633;">getX</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>, coord.<span style="color: #006633;">getY</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">+</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>;
		buildCastle<span style="color: #009900;">&#40;</span>map.<span style="color: #006633;">getElementAt</span><span style="color: #009900;">&#40;</span>coord.<span style="color: #006633;">getX</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">+</span><span style="color: #cc66cc;">1</span>, coord.<span style="color: #006633;">getY</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>;
		buildCastle<span style="color: #009900;">&#40;</span>map.<span style="color: #006633;">getElementAt</span><span style="color: #009900;">&#40;</span>coord.<span style="color: #006633;">getX</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">+</span><span style="color: #cc66cc;">1</span>, coord.<span style="color: #006633;">getY</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>;
		buildCastle<span style="color: #009900;">&#40;</span>map.<span style="color: #006633;">getElementAt</span><span style="color: #009900;">&#40;</span>coord.<span style="color: #006633;">getX</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">+</span><span style="color: #cc66cc;">1</span>, coord.<span style="color: #006633;">getY</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">+</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>;
	<span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p><strong>Variation fonctionnelle</strong><br />
J&#8217;ai gardé le type de données, les conditions d&#8217;arrêt sont identiques. La récursion est un peu plus complexe a cause du foldl, mais on a une liste de cases adjacentes plutôt que du code dupliqué, c&#8217;est toujours ça de pris.</p>

<div class="wp_syntax"><div class="code"><pre class="haskell haskell" style="font-family:monospace;"><span style="color: #06c; font-weight: bold;">data</span> Castle <span style="color: #339933; font-weight: bold;">=</span> Castle <span style="color: green;">&#123;</span> castleCoords <span style="color: #339933; font-weight: bold;">::</span> <span style="color: green;">&#91;</span>Coords<span style="color: green;">&#93;</span> <span style="color: green;">&#125;</span>
&nbsp;
buildCastle <span style="color: #339933; font-weight: bold;">::</span> Map <span style="color: #339933; font-weight: bold;">-&gt;</span> Castle <span style="color: #339933; font-weight: bold;">-&gt;</span> Coords <span style="color: #339933; font-weight: bold;">-&gt;</span> Castle
buildCastle m c xy
  | <span style="font-weight: bold;">not</span> <span style="color: green;">&#40;</span>canRecruitUnits m xy<span style="color: green;">&#41;</span> <span style="color: #339933; font-weight: bold;">=</span> c
  | xy `<span style="font-weight: bold;">elem</span>` <span style="color: green;">&#40;</span>castleCoords c<span style="color: green;">&#41;</span> <span style="color: #339933; font-weight: bold;">=</span> c
  | <span style="font-weight: bold;">otherwise</span> <span style="color: #339933; font-weight: bold;">=</span> <span style="font-weight: bold;">foldl</span> <span style="color: green;">&#40;</span>buildCastle m<span style="color: green;">&#41;</span> c' <span style="color: green;">&#40;</span>near xy<span style="color: green;">&#41;</span>
  <span style="color: #06c; font-weight: bold;">where</span>
    c' <span style="color: #339933; font-weight: bold;">=</span> Castle <span style="color: green;">&#40;</span>xy:<span style="color: green;">&#40;</span>castleCoords c<span style="color: green;">&#41;</span><span style="color: green;">&#41;</span>
    variations x <span style="color: #339933; font-weight: bold;">=</span> <span style="color: green;">&#91;</span>x<span style="color: #339933; font-weight: bold;">-</span><span style="color: red;">1</span><span style="color: #339933; font-weight: bold;">,</span> x<span style="color: #339933; font-weight: bold;">,</span> x<span style="color: #339933; font-weight: bold;">+</span><span style="color: red;">1</span><span style="color: green;">&#93;</span>
    near <span style="color: green;">&#40;</span>x<span style="color: #339933; font-weight: bold;">,</span> y<span style="color: green;">&#41;</span> <span style="color: #339933; font-weight: bold;">=</span> <span style="color: green;">&#91;</span><span style="color: green;">&#40;</span>a<span style="color: #339933; font-weight: bold;">,</span> b<span style="color: green;">&#41;</span> | a <span style="color: #339933; font-weight: bold;">&lt;-</span> variations x<span style="color: #339933; font-weight: bold;">,</span> b <span style="color: #339933; font-weight: bold;">&lt;-</span> variations y<span style="color: #339933; font-weight: bold;">,</span> <span style="color: green;">&#40;</span>a<span style="color: #339933; font-weight: bold;">,</span> b<span style="color: green;">&#41;</span> `isInMap` m <span style="color: #339933; font-weight: bold;">&amp;&amp;</span> <span style="color: green;">&#40;</span>a<span style="color: #339933; font-weight: bold;">,</span> b<span style="color: green;">&#41;</span> <span style="color: #339933; font-weight: bold;">/=</span> <span style="color: green;">&#40;</span>x<span style="color: #339933; font-weight: bold;">,</span> y<span style="color: green;">&#41;</span><span style="color: green;">&#93;</span></pre></div></div>

<p><strong>Variation simplifiée</strong><br />
La dernière en date. Finalement, je n&#8217;ai pas besoin de type de données particulier, vérifier si les deux coordonnées sont dans la liste qui constitue un château me suffit. J&#8217;ai repris l&#8217;idée de la liste des cases adjacentes (growable), mais l&#8217;itération dessus me semble plus claire que le foldl.</p>

<div class="wp_syntax"><div class="code"><pre class="python python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">class</span> Board:
  <span style="color: #808080; font-style: italic;">#...</span>
  <span style="color: #ff7700;font-weight:bold;">def</span> buildCastle<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, x, y, accumulator<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: black;">&#40;</span>x, y<span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">in</span> accumulator <span style="color: #ff7700;font-weight:bold;">or</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #008000;">self</span>.<span style="color: black;">isCastleArea</span><span style="color: black;">&#40;</span>x, y<span style="color: black;">&#41;</span>:
      <span style="color: #ff7700;font-weight:bold;">return</span> accumulator
&nbsp;
    accumulator.<span style="color: black;">append</span><span style="color: black;">&#40;</span> <span style="color: black;">&#40;</span>x, y<span style="color: black;">&#41;</span> <span style="color: black;">&#41;</span>
    growable = <span style="color: black;">&#91;</span><span style="color: black;">&#40;</span>a, b<span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">for</span> a <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: black;">&#40;</span>x-<span style="color: #ff4500;">1</span>, x, x+<span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>
                       <span style="color: #ff7700;font-weight:bold;">for</span> b <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: black;">&#40;</span>y-<span style="color: #ff4500;">1</span>, y, y+<span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>
                       <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">self</span>.<span style="color: black;">isInBoard</span><span style="color: black;">&#40;</span>a, b<span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">and</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: black;">&#40;</span>a, b<span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">in</span> accumulator<span style="color: black;">&#93;</span>
    <span style="color: #ff7700;font-weight:bold;">for</span> x, y <span style="color: #ff7700;font-weight:bold;">in</span> growable:
      <span style="color: #008000;">self</span>.<span style="color: black;">buildCastle</span><span style="color: black;">&#40;</span>x, y, accumulator<span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> accumulator</pre></div></div>

]]></content:encoded>
			<wfw:commentRss>http://blog.vfiack.fr/17-variations-sur-un-theme/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Un parser très basique avec JParsec</title>
		<link>http://blog.vfiack.fr/7-un-parser-tres-basique-avec-jparsec/</link>
		<comments>http://blog.vfiack.fr/7-un-parser-tres-basique-avec-jparsec/#comments</comments>
		<pubDate>Mon, 05 Jan 2009 21:51:16 +0000</pubDate>
		<dc:creator>vfiack</dc:creator>
		
		<category><![CDATA[Développement]]></category>

		<category><![CDATA[JParsec]]></category>

		<guid isPermaLink="false">http://blog.vfiack.fr/?p=7</guid>
		<description><![CDATA[Un exemple très simple d'utilisation de JParsec.]]></description>
			<content:encoded><![CDATA[<p>Juste pour ma mémoire, comme j&#8217;ai passé la matinée là dessus sans trouver comment renvoyer des données&#8230;</p>
<p>On a un document très simple à parser :</p>

<div class="wp_syntax"><div class="code"><pre class="json" style="font-family:monospace;">{abc|123|tralala}
{cde||youpie|tsoin tsoin|}</pre></div></div>

<p>On veut évidement récupérer des listes de chaines, sans se poser de question. Tellement simple qu&#8217;on pourrait le faire a la main. Mais voilà, moi, j&#8217;avais envie d&#8217;essayer <a href="http://jparsec.codehaus.org/">JParsec</a>, et tous les exemples sont terriblement plus compliqués (et surtout, plus orientés langages et opérations).</p>
<p>L&#8217;idée de parsec, c&#8217;est de faire des parsers directement dans le langage du programme, et de les combiner, plutôt que de rédiger une grammaire qui sera convertie (genre <a href="http://www.antlr.org/">antlr</a>). Ce qui me plait la dedans, c&#8217;est l&#8217;impression de pouvoir y aller progressivement.</p>
<p>Bref.</p>
<p>L&#8217;essentiel du boulot est dans la classe <a href="http://jparsec.codehaus.org/jparsec2/api/org/codehaus/jparsec/Scanners.html">Scanners</a>. Pensez à regarder les méthodes, et pas que les champs, c&#8217;est ce qui m&#8217;a foutu dedans ce matin (on va dire que j&#8217;étais fatigué).</p>
<p>Donc pour éviter d&#8217;avoir a préfixer tout ce qu&#8217;on va appeler :</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="java java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">static</span> org.<span style="color: #006633;">codehaus</span>.<span style="color: #006633;">jparsec</span>.<span style="color: #006633;">Scanners</span>.*;</pre></td></tr></table></div>

<p>Et on combine. Commençons par ce qu&#8217;on veut récupérer, c&#8217;est a dire les caractères entre les pipes :</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="java java" style="font-family:monospace;">Parser<span style="color: #339933;">&lt;</span>String<span style="color: #339933;">&gt;</span> content <span style="color: #339933;">=</span> notAmong<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;|}&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">many</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">source</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;</pre></td></tr></table></div>

<p>La méthode source(), c&#8217;est l&#8217;astuce pour récupérer le texte qui matche. Je ne comprends pas pourquoi ces parseurs ne renvoient pas la chaine directement.</p>
<p>Une fois qu&#8217;on a cette chaine, on peut récupérer une liste, puis la ligne complète :</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>2
3
</pre></td><td class="code"><pre class="java java" style="font-family:monospace;">Parser<span style="color: #339933;">&lt;</span>List<span style="color: #339933;">&lt;</span>String<span style="color: #339933;">&gt;&gt;</span> enclosed <span style="color: #339933;">=</span> content.<span style="color: #006633;">sepBy</span><span style="color: #009900;">&#40;</span>isChar<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'|'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>;
Parser<span style="color: #339933;">&lt;</span>List<span style="color: #339933;">&lt;</span>String<span style="color: #339933;">&gt;&gt;</span> line <span style="color: #339933;">=</span> enclosed.<span style="color: #006633;">between</span><span style="color: #009900;">&#40;</span>isChar<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'{'</span><span style="color: #009900;">&#41;</span>, isChar<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'}'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>;</pre></td></tr></table></div>

<p>Il ne nous reste plus qu&#8217;a boucler sur les lignes :</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>4
5
6
</pre></td><td class="code"><pre class="java java" style="font-family:monospace;">Parser<span style="color: #339933;">&lt;</span>Void<span style="color: #339933;">&gt;</span> eof <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>Parser<span style="color: #339933;">&lt;</span>Void<span style="color: #339933;">&gt;</span><span style="color: #009900;">&#41;</span>Parsers.<span style="color: #006633;">EOF</span>; 
Parser<span style="color: #339933;">&lt;</span>Void<span style="color: #339933;">&gt;</span> endOfLine <span style="color: #339933;">=</span> among<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;rn&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">or</span><span style="color: #009900;">&#40;</span>eof<span style="color: #009900;">&#41;</span>;
Parser<span style="color: #339933;">&lt;</span>List<span style="color: #339933;">&lt;</span>List<span style="color: #339933;">&lt;</span>String<span style="color: #339933;">&gt;&gt;&gt;</span> lines <span style="color: #339933;">=</span> line.<span style="color: #006633;">endBy</span><span style="color: #009900;">&#40;</span>endOfLine<span style="color: #009900;">&#41;</span>;</pre></td></tr></table></div>

<p>Et voilà, on y est :</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>7
</pre></td><td class="code"><pre class="java java" style="font-family:monospace;"><span style="color: #003399;">System</span>.<span style="color: #006633;">out</span>.<span style="color: #006633;">println</span><span style="color: #009900;">&#40;</span>lines.<span style="color: #006633;">parse</span><span style="color: #009900;">&#40;</span>document<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>;</pre></td></tr></table></div>

<p>=> <code>[[abc, 123, tralala], [cde, , youpie, tsoin tsoin, ]]</code></p>
<p>Résultat des opérations : 6 lignes de code pour récupérer des données structurées.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.vfiack.fr/7-un-parser-tres-basique-avec-jparsec/feed/</wfw:commentRss>
		</item>
	</channel>
</rss>

