Explorando los autómatas celulares cíclicos con PNGwriter
Esta es una implementación simple de un Autómata Celular Cíclico. Las reglas son las siguientes:
- Inicializa un arreglo 2D con valores aleatorios entre 0 y el máximo número de estado que puede alcanzar la célula.
- Si una célula tiene por lo menos un vecino cuyo valor es mayor en 1, esa célula es comida por el vecino (el valor cambia a ser el del vecino).
- Células con valor máximo de nivel sólo pueden ser comidas por células con valor 0. En ese caso, el valor va a 0, y de ahí el nombre de espacio cíclico.
- Repite los últimos dos pasos y eventualmente aparecerán patrones estables.
Para más información sobre los autómatas celulares, ve la página de Wikipedia, Cellular Automaton y el otro ejemplo de PNGwriter de autómatas celulares.
Aquí hay algunas imágenes generadas con 14 niveles.
0 iteraciones |
15 iteraciones |
30 iteraciones |
50 iteraciones |
La secuencia de imágenes puede ser fácilmente combinada en una película. Usé Quicktime Player de Apple (File --> Open Image Sequence...). Las películas pueden ser vistas aquí:The movies can be found here: Películas. Están en formato .mov y .avi. Los .avi tienen menor calidad de imagen. El nombre del archivo contiene informacioón acerca de cuántos cuadros contiene, cuántos niveles fueron usados como parte de las reglas, y si se consideraron 4 u 8 vecinos. Mándame un email al email que sale en Contactos si el link a pas películas no funciona, como está en un servidor distinto.
Aquí está el código:
/* Cyclic Space - Example program for PNGwriter
* http://pngwriter.sourceforge.net/
* By Paul Blackburn */
#include <pngwriter.h>
#include <stdlib.h>
#include <time.h>
#define rand_max 2147483647
int main()
{
int width = 300;
int height = 300;
int maxiter = 500;
// Create the PNGwriter instance.
pngwriter out(width, height, 0, "out.png");
int k, i, j;
// Create old and new grids
int ** grid;
grid = new int * [width];
for(k = 0; k < width; k++)
{
grid[k] = new int [height];
}
int ** newgrid;
newgrid = new int * [width];
for(k = 0; k < width; k++)
{
newgrid[k] = new int [height];
}
// Seed random number generator
int maxstates = 14;
srandom( time(NULL) );
//Grid initially randomized.
for(i = 0; i < width; i++)
{
for(j = 0; j < height; j++)
{
grid[i][j] = random()%maxstates;
}
}
// Copy to other grid
for(i = 0; i < width; i++)
{
for(j = 0; j < height; j++)
{
newgrid[i][j] = grid[i][j];
}
}
int jp, jm, ip, im;
// Start iterating
for(int iteration = 0; iteration < maxiter; iteration++)
{
for(i = 0; i < width; i++)
{
for(j = 0; j < height; j++)
{
jp = j+1;
jm = j-1;
ip = i+1;
im = i-1;
//Cyclic boundary conditions.
if(im == -1)
{
im = width-1;
}
if(ip == width)
{
ip = 0;
}
if(jm == -1)
{
jm = height-1;
}
if(jp == height)
{
jp = 0;
}
// Rules
if(
( (grid[im][j] == 0) ||
(grid[ip][j] == 0) ||
(grid[i][jm] == 0) ||
(grid[i][jp] == 0)
|| (grid[im][jm] == 0) ||
(grid[ip][jp] == 0) ||
(grid[ip][jm] == 0) ||
(grid[im][jp] == 0) )
&&
( grid[i][j] == (maxstates-1) )
)
{
newgrid[i][j] = 0;
continue;
}
if(
( (grid[im][j] == grid[i][j]+1) ||
(grid[ip][j] == grid[i][j]+1) ||
(grid[i][jm] == grid[i][j]+1) ||
(grid[i][jp] == grid[i][j]+1)
|| (grid[im][jm] == grid[i][j]+1) ||
(grid[ip][jp] == grid[i][j]+1) ||
(grid[ip][jm] == grid[i][j]+1) ||
(grid[im][jp] == grid[i][j]+1)
)
)
{
newgrid[i][j] = grid[i][j]+1;
continue;
}
}
}
// Copy old grid to new grid
for(i = 0; i < width; i++)
{
for(j = 0; j < height; j++)
{
grid[i][j] = newgrid[i][j];
}
}
// Plot the result, with level of red according to the state that pixel is in.
for(i = 0; i < width; i++)
{
for(j = 0; j < height; j++)
{
out.plot(i+1,j+1, ((double) grid[i][j])/(maxstates-1), 0.0, 0.0);
}
}
// Rename this instance given the iteration number.
out.pngwriter_rename((unsigned long int) iteration);
// Write the file to disk.
out.close();
} //iteration
// Delete grids.
for(k = 0; k < width; k++)
{
delete [] grid[k];
}
delete [] grid;
for(k = 0; k < width; k++)
{
delete [] newgrid[k];
}
delete [] newgrid;
return 0;
}
syntax highlighted by Code2HTML, v. 0.9.1
|
|