Saltar al contenido

¿Cómo crear una hormiga de Langton en látex?

Hemos estado indagando en diferentes foros y así brindarte la respuesta a tu problema, en caso de dudas puedes dejarnos tu pregunta y respondemos con mucho gusto.

Solución:

Aquí hay un enfoque simple en Metapost envuelto en el luamplib biblioteca – compilar con lualatex.

RequirePackageluatex85
documentclass[border=5mm]standalone
usepackageluamplib
begindocument
mplibtextextlabelenable
mplibnumbersystemdouble
beginmplibcode
beginfig(1);
    numeric x,y,N; 
    boolean s[][];
    pair heading;
    N = 1000; 
    x = y = 0;
    heading = up;

    for i=0 upto N:
        if not known s[x][y]: s[x][y] := false; fi

        if s[x][y]:
            s[x][y] := false;
            heading := round(heading rotated -90);
        else:
            s[x][y] := true;
            heading := round(heading rotated 90);
        fi

        x := x + xpart heading;
        y := y + ypart heading;

     endfor

     z0 = (x,y);

     numeric n;
     n = 42;
     for x=-n upto n:
         for y=-n upto n:
             if known s[x][y]:
                 if s[x][y]:
                     drawdot 3(x,y) withpen pencircle scaled 2;
                 fi
             fi
         endfor
     endfor
     drawdot 3z0 withpen pencircle scaled 2.2 withcolor 2/3 red;
     %label.urt(decimal N, 3(-n,-n));

endfig;
endmplibcode
enddocument

Con N=1000 (como arriba), debería obtener algo como esto:

ingrese la descripción de la imagen aquí

Si lo subes un poco y lo pones N=10000, entonces obtienes esto:

ingrese la descripción de la imagen aquí

y luego a eso de N=10200 la “autopista” comienza a aparecer, así que con N=11000 usted obtiene:

ingrese la descripción de la imagen aquí

Nota sobre el tamaño y la precisión de los números

En Metapost simple (incluso cuando está envuelto en luamplib) el sistema numérico predeterminado es el sistema “escalado” de Knuth, donde el mayor valor absoluto permitido es un poco menos de 4096. Por lo tanto, agregué mplibnumbersystemdouble para poder configurar N a valores superiores a 4096, de modo que podamos ver la interesante marcha de la hormiga.

Esto tiene el irritante efecto secundario de hacer que los resultados de operaciones simples sean menos exactos que en el sistema predeterminado. Entonces, con el sistema numérico predeterminado, cuando configuro

heading = up;

heading obtiene el valor (0,1) para que cuando me ponga

heading := heading rotated 90;

heading se convierte en (-1,0), y ambos xpart heading y ypart heading siempre se ven como números enteros, por lo que puedo agregarlos al x y y índices de forma segura.

Pero con el double sistema de numeración

heading := heading rotated 90;

conjuntos heading para (-1,6.123233995736766e-17) que no es exactamente lo mismo y significa que las partes no se pueden usar para agregar a los índices.

Mi solución a esta irritación fue agregar round() de modo que los números diminutos se redondeen a cero según sea necesario. round() se define de modo que si lo aplica a un pair variable redondea ambas partes.

Aquí hay una solución LaTeX que usa tikz para dibujar el mundo. Las reglas de la hormiga de Langton según Wikipedia:

  • En un cuadrado blanco, gire 90 ° a la derecha, voltee el color del cuadrado, avance una unidad.

  • En un cuadrado negro, gire 90 ° a la izquierda, voltee el color del cuadrado, avance una unidad.

La posición y dirección de la hormiga está indicada por una flecha roja.

% Langton's ant
documentclass[tikz]standalone
usepackagetikz

% boundaries of the known universe
% The boundaries expand automatically as the ant runs.
% If you want to have a stable map that does not expand,
% set the boundaries to some values large enough before letting the ant run.
newcounterN
newcounterE
newcounterS
newcounterW

% position and direction of ant
newcounterantx
newcounteranty
newcounterantdir% 0=N, 1=E, 2=S, 3=W

% ifIsWhiteSquarexycode for whitecode for black
% white = "square:x:y is undefined", black = "square:x:y is defined"
newcommandifIsWhiteSquare[4]ifcsname square:#1:#2endcsname#4else#3fi
newcommandsetwhite% equate square:x:y with an undefined macro
  expandafterletcsname square:arabicantx:arabicantyendcsnameundefined
newcommandsetblack% define square:x:y as a macro expanding to nothing
  expandafterdefcsname square:arabicantx:arabicantyendcsname
newcommandturnright% +1 mod 4
  stepcounterantdirifnumvalueantdir>3addtocounterantdir-4fi
newcommandturnleft% -1 mod 4
  addtocounterantdir3ifnumvalueantdir>3addtocounterantdir-4fi
newcommandstepforward% add +1/-1 to antx/anty and expand known universe
  ifcasevalueantdir%
     stepcounteranty%
     ifnumvalueanty>valueNstepcounterNfi
   or
     stepcounterantx%
     ifnumvalueantx>valueEstepcounterEfi
   or
     addtocounteranty-1%
     ifnumvalueanty

ingrese la descripción de la imagen aquí

La imagen gif fue generada por el comando

convert -density 300 -delay 30 -loop 0 -background white -alpha remove ant.pdf ant.gif

La solución pura de LaTeX es más lenta que las versiones de Lualatex, pero aún lo suficientemente rápida para hacer 12000 pasos en fracciones de segundo (más rápido de lo que se necesita para dibujar la imagen final).

ingrese la descripción de la imagen aquí

Requiere lualatex. Como de costumbre, la traducción de lua para tikz es un poco torpe y para mayor rapidez solo se extraen las celdas coloreadas y se pasan a la parte de dibujo.

RequirePackageluatex85
documentclass[tikz,border=5]standalone
begindocument
directlua
minx = 1; miny = 1; maxx = -1; maxy = -1
x = 0; y = 0; a = 0; t = ; p = ; n = 0
for i = 0,10000 do
  if x > maxx then maxx = x end; if x < minx then minx = x end
  if y > maxy then maxy = y end; if y < miny then miny = y end
  t[x] = t[x] or 
  t[x][y] = 1 - (t[x][y] or 0)
  a = a - (t[x][y] * 2 - 1) * 90
  if a < 0 then a = a + 360 end; if a >= 360 then a = a - 360 end
  x = x + ((a == 0) and 1 or 0) - ((a == 180) and 1 or 0)
  y = y + ((a == 90) and 1 or 0) - ((a == 270) and 1 or 0)
end
for j = minx,maxx do; for i = miny,maxy do
  if (t[j] or )[i] == 1 then
    n = n + 1
    p[n] = '(' .. j .. ',' .. i .. ')'
  end
end; end
ant = '(' .. x .. ',' .. y .. ')'

edefndirectluatex.print(n)
begintikzpicture[fill1/.style=fill=black, x=1pt, y=-1pt]
foreach i in 1,...,nfill directluatex.print(p[i]) circle [radius=0.5];
fill[red] directluatex.print(ant) circle [radius=0.375];
endtikzpicture
enddocument

ingrese la descripción de la imagen aquí

Y aquí hay una variante más colorida donde la sombra se determina como el número de visitas a una celda módulo 20:

RequirePackageluatex85
documentclass[tikz,border=5]standalone
usepackageluacode
begindocument
beginluacode*
minx = 1; miny = 1; maxx = -1; maxy = -1
x = 0; y = 0; a = 0; t = ; p = ; b = ; n = 0
for i = 0,10500 do
  if x > maxx then maxx = x end; if x < minx then minx = x end
  if y > maxy then maxy = y end; if y < miny then miny = y end
  t[x] = t[x] or 
  t[x][y] = ((t[x][y] or 0) + 1) % 20
  a = a - ((((t[x][y] % 2) == 0) and 1 or 0)* 2 - 1) * 90
  if a < 0 then a = a + 360 end; if a >= 360 then a = a - 360 end
  x = x + ((a == 0) and 1 or 0) - ((a == 180) and 1 or 0)
  y = y + ((a == 90) and 1 or 0) - ((a == 270) and 1 or 0)
end
for j = minx,maxx do; for i = miny,maxy do
  c = (t[j] or )[i] or 0
  if c > 0 then
    n = n + 1
    p[n] = '[fill' .. c .. '/.try] (' .. j .. ',' .. i .. ')'
      b[n] = c
end; end 
end
ant = '(' .. x .. ',' .. y .. ')'
endluacode*
edefndirectluatex.print(n)
begintikzpicture[x=-5pt,y=5pt]
foreach i [evaluate=o=directluatex.printb[i]*5;] in 1,...,n
  fill directluatex.print(p[i]) [blue!o] circle [radius=0.5];
fill[red] directluatex.print(ant) circle [radius=0.375];
endtikzpicture
enddocument

ingrese la descripción de la imagen aquí

Recuerda algo, que tienes la opción de aclarar si hallaste tu dilema .

¡Haz clic para puntuar esta entrada!
(Votos: 2 Promedio: 4)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *