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:
Si lo subes un poco y lo pones N=10000
, entonces obtienes esto:
y luego a eso de N=10200
la “autopista” comienza a aparecer, así que con N=11000
usted obtiene:
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
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).
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
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
Recuerda algo, que tienes la opción de aclarar si hallaste tu dilema .