We are about to switch to a new forum software. Until then we have removed the registration on this forum.
@daddydean -- if you want pixels to be moving through a grid with no negative space, then you probably want pixel swapping behaviors -- and it is quite likely that your swapping behaviors are part of a cellular automaton for pixels.
The good news is that there is tons of code out there (and on this forum) for cellular automata.
There is some bad news. One is that writing simple rules for pixel swapping (for example, giving each pixel a goal location and having it swap in the direction of that goal) and then applying it to every pixel in a grid will create some pretty crazy artifacts -- stable spaces of pixels in the final arrangement that seem to have nothing to do with your understanding of the original values and the goals.
For just one example, two pixels facing in the same direction may be frozen forever swapping with each other. This can create bands, dead zones, and all kinds of oddities where you expect pixels to self-organize nicely.
Thing get a bit better if you add complications like:
Approaches like these can things can break up log-jams and create more fluid outcomes.
There is more bad news, however. 2D cellular automata are not reversible unless they are broken into blocks and each block is updated with an invertible function...
...so you aren't going to be able to play your 2D cellular automaton backwards algorithmically. Two approaches that might work, however:
record every frame (of data or an image), like a movie, then play the frame recordings back in reverse order, or:
Pair every single pixel in the outcome with a target pixel in the original image, then have them seek again until they finally reassemble the original image -- it almost certainly won't be the same shuffle, but it will arrive at the origin.
Models of a big group of things all shuffling around in a space and heading in their own directions is actually of interest in flocking, traffic analysis, et cetera. Normally the space isn't perfectly dense the way an image is, but see for example "A Cellular Automaton model for pedestrian counterflow with swapping" https://www.sciencedirect.com/science/article/pii/S037843711730122X
edit post, highlight code, press ctrl-o to format.
the pdf examples linked to from the libraries part of the website are some of the best documentation there.
that said, 'automata' and 'pdf' isn't a great match
help, I am a complete beginner.. I found this code on open processing and I would like to export the frames in pdf. who can help me? thank you very much
code cellular automata:
class CellularAutomata
{
// tape: a tape of symbols indexed by integers
int[] tape;
// NS: the neighborhood size
int NS = 7;
// ruleset: an array encoding the rules of this cellular automata
int[] ruleset;
// iterations: the iteration count
int iterations;
// maxIterations: the maximum number of iterations we will draw on the canvas
int maxIterations;
CellularAutomata(int N)
{
// randomly initialize the tape contents
tape = new int[N];
for(int i = 0; i < tape.length; i++)
{
tape[i] = (int)random(2);
}
maxIterations = (tape.length)*(height/width);
iterations = 0;
ruleset = new int[(int)pow(2,NS)];
for(int i = 0; i < ruleset.length; i++)
{
ruleset[i] = (int)random(2);
}
}
// based on the tape contents and the cellular automata's rules, update the tape contents
void updateTape()
{
// because we want the update process to be a synchronous one, we need to store the updated contents on an auxiliary array
int[] newtape = new int[tape.length];
// for each position 'i' in the tape
for(int i = 0; i < tape.length; i++)
{
// we take the tape contents in the positions adjacent to 'i'
int[] neighbor = new int[NS];
for(int j = 0; j < NS; j++)
{
neighbor[j] = tape[ (i+(j-(int)(NS/2))+tape.length)%(tape.length) ];
}
// we compute the updated state for position 'i' through the cellular automata's rules
newtape[i] = rules(neighbor);
}
// now we can replace the old tape with the updated contents
tape = newtape;
iterations++;
}
/**
we can very easily encode a ruleset through an array of length 2^NS
reasoning:
1. there are 2^NS possible combinations of values for the NS binary variables in 'neighbors'
2. the rule for each of these combinations can be encoded on a given index of an (2^NS)-sized array
3. we can sort these combinations through a lexicographic ordering
*/
int rules(int[] neighbor)
{
int index = 0;
for(int i = 0; i < NS; i++)
{
index += ((int)pow(2,NS-i-1))*neighbor[i];
}
return ruleset[index];
}
void draw()
{
for(int i = 0; i < tape.length; i++)
{
if(tape[i] == 1) fill(255);
else fill(0);
// L: cell side length
float L = float(width)/float(tape.length);
rect
(
i*L,
iterations*L,
L,
L
);
}
}
}
CellularAutomata CA;
void setup()
{
size(512,512);
background(0);
noStroke();
frameRate(10000);
CA = new CellularAutomata(width);
}
void draw()
{
CA.draw();
CA.updateTape();
}
void mousePressed()
{
background(0);
CA = new CellularAutomata(width);
draw();
}
I'm trying to implement a simple cellular automata in processing and I've run into a strange problem. My code is here. I have a methods that change the state of two arrays, currentArray and nextArray, but for some reason I am having trouble changing the values in the array. I run the program and any changes I make don't seem to stick. Is this some sort of scope problem? I'd appreciate any help you can offer.
made a sketch to find the rule for game of life for the 9-bit automata above
import java.math.*;
BigInteger gol;
int n;
boolean alive;
void setup(){
gol= new BigInteger("0");
for (int i=0; i<512; i++){
n=0;
for (int j=0; j<9; j++){
if (j!=4){
n+= (i >> j)&1;
}
}
alive=((i>>4)&1)==1;
if ( alive && n==2 ){ gol = gol.setBit(i+1); }
if(n==3){ gol = gol.setBit(i+1);
}
}
println(gol.toString());
}
turns out to be
95269658970504075026401947768164943776577911284651056525821775275694548745963441068740035536685992072438984633721408802547302109256447217920
rule = the "seed" you change to get new results state = a number representing a state you wish to convert into an output
I may not have been clear about it, the rules are given to the cellular automata at its initialisation. Still, maybe it's possible to obtain the rule
value from the rules, which seems possible since it has to be calculated only once.
If you wanna look at my code :
class CellAut {
protected int[] cells,
dim, //size in each dimension
dimSize;
protected boolean[] junctions;
protected int[][] neighbors,
rules;
color[] states;
CellAut(int[] dim, boolean[] junctions, color[] states, int[][] rules) {
this.dim = dim;
dimSize = new int[dim.length];
dimSize[0] = 1;
for (int i = 0; i < dim.length - 1; i++) dimSize[i + 1] = dimSize[i] * dim[i];
this.junctions = junctions;
this.states = states;
}
void iterate() {
for (int i = 0; i < cells.length; i++) {
int[] coords = getCoords(i);
int[] neighborStates = new int[states.length];
for (int neighborIndex : getNeighborsIndexes(coords)) {
neighborStates[cells[neighborIndex]]++;
}
}
}
int[] getNeighborsIndexes(int[] coords) {
int[] neighborsIndexes = new int[neighbors.length];
for (int i = 0; i < neighbors.length; i++) {
boolean exists = true;
int[] neighborCoords = new int[dim.length];
for (int d = 0; d < dim.length; d++) {
int coordD = coords[d] + neighbors[i][d];
exists &= coordD < dim[d] || junctions[d];
if (!exists) break;
neighborCoords[d] = coordD % dim[d];
}
neighborsIndexes[i] = exists ? getRuleIndex(neighborCoords) : -1;
}
return neighborsIndexes;
}
int getRule(int actualState, int... statesCount) {
if (statesCount.length != states.length) return -1;
//TODO
}
boolean setRule(int state, int actualState, int... statesCount) {
if (statesCount.length != states.length || state < 0 || state >= states.length) return false;
rules[actualState][getRuleIndex(statesCount)] = state;
return true;
}
protected int[] getCoords(int index) {
int[] coords = new int[dim.length];
for (int i = 0; i < dim.length - 1; i++) {
coords[i] = (index % dimSize[i + 1]) / dimSize[i];
index -= coords[i];
}
coords[dim.length - 1] = index / dimSize[dim.length - 1];
return coords;
}
}
This explanation of 8 states and 8 outputs is relevant ...
Just treat rule as a concatenation of the 3 bit results for each of the 8 possible inputs. For example, if you map 0-4 to 6, 5 to 0, and 6-7 to 7, the bits of rule might look like (going from 7-0, parentheses added just for clarity): (111)(111)(000)(011)(011)(011)(011)(011) Then to pick a specific result out of rule, you can use shift and bitwise and. For example, if n = 4, we shift rule right by 4*3 bits: (111)(111)(000)(011) And then we do a bitwise and with 7: (011)
In other words, it'd just be return (rule >> (n*3)) & 7;
I probably have a few extra parentheses in there, but I'm too lazy to double-check precedence. - ErasmusDarwin
So, It's hard to know exactly what you want when you say S and N,
But just assuming you want 4 neighbors that can be 0 or 1, and want as many states as possible from them you get 16 states, and mapped to 0 or 1, that's 2 output's
so 2^16 ≈ 65K rules
You don't store these rules, you calculate them on the fly as such...
state = (Neigbour1?1:0)+(Neighbour2?2:0)+(Neighbour3?4:0)+(Neighbour4?8:0);
cell = (( ( rule >> state ) & 1) == 1) ? 1:0;
If you want more possibilities than 4-neighbors 0/1 use this guideline
rule = the "seed" you change to get new results
state = a number representing a state you wish to convert into an output
n = least number of bits needed to represent highest output
o = highest output
( rule >> ( state * n ) ) & o;
This works guaranteed. If you don't know how to use it or tweak it, read the quote at the top or show your code and what you want it to do I'll show you where to put it.
or an example how to use it in practice in Wolfram automata, but it's the same principle... look at line 16 and 17
int swap,xyz=200,rule=0;
boolean[][][] fields = new boolean[2][xyz][xyz];
void clear() {
for(int b=0;b<2;b++){
for (int x=0;x < xyz; x++) {
for (int y = 0; y < xyz; y++) {
fields[b][x][y] = 0;}}}
}
void setup(){size(200,216);clear();loadPixels();}
boolean algorithm(int d,int x0,int y0) {
fields[0][100][0] = fields[1][100][0] = 1;
up=(y0+xyz-1)%xyz;
boolean n1=fields[swap][(x0+xyz-1)%xyz][up];
boolean m=fields[swap][x0][up];
boolean n2=fields[swap][(x0+1)%xyz][up];
int state = (n1?4:0)+(m?2:0)+(n2?1:0);
return (((rule >> state) & 1) == 1)?1:0;
}
void draw() {
for (int y=0;y<xyz;y++){
for (int x=0;x<xyz;x++){
fields[(swap+1)%2][x][y]=algorithm(0,x,y);
pixels[x+xyz*y]=algorithm(0,x,y)?#000000:#ffffff;}}
if(swap==0){swap=1; updatePixels();}else{swap=0;}
fill(0);rect(0,xyz,xyz,16);fill(255);
textSize(12);text("Rule = #"+str(rule),12,xyz+12);
}
void mouseClicked(){ if (mouseButton==LEFT) {clear();rule++;}
else if (mouseButton==RIGHT){clear();rule--;} rule=abs(rule%256);}
@yaya671 -- This is unclear to me:
we count the number of neighbors in each state and then use a list of rules indicating what state is gonna take that cell in function of the number of neighbors in each state and the cell's actual state.
Do you mean like this?
int cellUpdate (int cellState, int[] neighborStateCounts, RuleList rules) {
int newState
... do something with rules ...
return newState;
}
I'm surprised that Shiffman's chapter section 7.6 wasn't helpful.
If you don't want to program your rules list there are options other than a sparse matrix -- in the general case you are essentially loading programmed rules from a data format into RuleList, e.g.:
state, neighborPattern, newstate
... where "neighborPattern" supplies a configuration to a boolean function that acts on neightborStateCounts and, if true, sets state to newstate.
Edit: looks like Chrisir beat me to some of this.
This dynamic programming problem isn't specific to cellular automata, by the way -- it would come up any time you asked "how to I parameterize a general purpose comparator?" The easiest way of all of course is to write your rules in Processing (that is, Java -- a general purpose programming language). You could also try to dynamically load Java rules (e.g. using ClassLoader / URLClassLoader) -- but I believe this can be extremely fiddly.
You could check previous related posts: https://forum.processing.org/two/search?Search=automata
Shiffman devotes a chapter in his book: http://natureofcode.com/book/chapter-7-cellular-automata/
Kf
Applied the celluar automata concept of looking at just two neighbours and putting white or black rather their color.
And rule 90 emerged again, together with rule 30.
I don't know how i'd apply this to the quanta though.
https://www.openprocessing.org/sketch/410830 <- EDIT:
rewrote the old code into a carbon copy of wolfram's automata, with rules in correct order
Also I looked at GLSL shaders which looked really difficult so I'll have to find some other way to speed things up for the 2D and 3D stuff, maybe multithreading or AVX, whatever works and isn't too big of a hurdle
This was supposed to be a celluar automata kind of thing but it was blinking so annoyingly.
Got a smoother turbulence thing going and added random painting to it which looks pretty cool in motion.
https://youtube.com/watch?v=cd-ZNymt6Ko&feature=youtu.be
newer video -> https://youtube.com/watch?v=cbCyq5RMXLk
leftclick, paint, rightclick erase
Update2,
Faster version any key changes "rule"
int button;
int speed;
int paint;
int xyz;
int vdit;
int[] field;
int[] b;
boolean closerThan(int distance,int x0,int y0){
int dx = x0-mouseX; dx*=dx;
int dy = y0-mouseY; dy*=dy;
return dx+dy<distance;}
int sts (int l){ return ((l%4==0)?0:2)*((floor(l/4)%2==1)?-1:1);}
int[] pbox(int n, int layer){
int px,py,xt,yt; xt=yt=0;
px=(layer%2==0)?0:1;
py=(layer<=1)?0:1;
if(n<=7){ xt=px==0?1:-1;}
else { yt=py==0?1:-1;}
xt += sts(n);
yt += sts(n+2);
return new int[]{xt,yt};
}
int[] pboxresult = new int[2];
int[][] overview = {
{ 1,2,3,2,3,0,3,-2, 1,-2,-1,-2,-1,0,-1,2,0,3,2,3,2, 1,2,-1,0,-1,-2,-1,-2, 1,-2,3},
{-1,2,1,2,1,0,1,-2,-1,-2,-3,-2,-3,0,-3,2,0,3,2,3,2, 1,2,-1,0,-1,-2,-1,-2, 1,-2,3},
{ 1,2,3,2,3,0,3,-2, 1,-2,-1,-2,-1,0,-1,2,0,1,2,1,2,-1,2,-3,0,-3,-2,-3,-2,-1,-2,1},
{-1,2,1,2,1,0,1,-2,-1,-2,-3,-2,-3,0,-3,2,0,1,2,1,2,-1,2,-3,0,-3,-2,-3,-2,-1,-2,1}
};
int[][] compare = new int[4][32];
int[][] transform = new int[4][32];
long RULE;
long randomlong(){
long result = floor(random(0,65536));
for(int i=0;i<3;i++){
result<<= 24;
result+=floor(random(0,16777216));
}
return result;
}
void compare_update(){
for(int i=0; i<4; i++){
for(int j=0; j<16; j++){
compare[i][j*2 ] = overview[i][j*2 ]; // map(overview[i][j*2 ],-width,width,-1,1);
compare[i][j*2+1] = overview[i][j*2+1]; // map( -height,height,-1,1);
}}}
void transform_update(){
for(int i=0; i<4; i++){
RULE = randomlong();
for(int j=0; j<16; j++){
pboxresult = pbox(int((RULE>>(j*4))&15),i);
transform[i][j*2 ]=pboxresult[0];
transform[i][j*2+1]=pboxresult[1];
}}}
void setup() {
size(384, 384);
xyz=width*height;
field=new int[xyz];
b=new int[xyz];
loadPixels();
compare_update();
new_rule();
}
void keyPressed(){
new_rule();
}
void new_rule(){
transform_update();
}
int frag(int p){
int x=p%width;
int y=p/width;
int comp=0;
int mine;
if(mousePressed && closerThan(speed,x,y)){
return paint;
} else {
int mylayer = (x%2==0?0:1)+(y%2==0?0:2);
mine = b[p];
for(int i =0; i<15; i++){
comp +=((b[((x+compare[mylayer][i*2]+(y+compare[mylayer][i*2+1])*width)+xyz)%xyz]<mine)?1:0);
}
return b[((x+transform[mylayer][comp*2]+(y+transform[mylayer][comp*2+1])*width)+xyz)%xyz];
}
}
void worker_a(){
for(int p=0; p<xyz; p++){
b[p]=pixels[p]=field[p];
}
}
void worker_b(){
for(int p=0; p<xyz; p++){
field[p]=frag(p);
}
}
void draw(){
println(frameRate);
if(mousePressed){
if( mouseButton == LEFT ){
button=1;
paint=floor(random(#000000,#ffffff));
} else{button =2; paint=#fffffe;}
}
else { button = 0; }
speed = int(sq(mouseX-pmouseX)+sq(mouseY-pmouseY)); // intentionally not using sqrt()
rect(0,0,width,height);
thread("worker_a");
thread("worker_b");
updatePixels();
}
Object oriented version
int paint;
int dis;
int speed;
int rulecounter;
int smooth = 1;
int xyz=256;
field g;
int randomcolor(){return floor(random(#000000,#ffffff));}
void setup(){size(256,256,P2D);g = new field();loadPixels();}
void draw() {
speed=floor(dist(pmouseX,pmouseY,mouseX,mouseY));
if(mousePressed){
if(mouseButton==LEFT) {
paint = randomcolor();
} else { paint = #ffffff; }
}
g.update();
g.display();
if(rulecounter++%100==0){g.randomrule();}
}
class field {
subdivision[][] rid;
long[] RULE;
field() {
RULE = new long[4];
randomrule();
int[] VAL;
rid = new subdivision[xyz][xyz];
for (int y = 0 ; y < xyz; y++) {
for (int x = 0 ; x < xyz; x++) {
VAL = new int []{#ffffff,#ffffff,#ffffff,#ffffff};
rid[x][y] = new subdivision(x,y,VAL,RULE);
}}
for (int y = 0 ; y < xyz; y++) {
for (int x = 0 ; x < xyz; x++) {
rid[x][y].set_neighbours(this.rid);
}}
}
long randomlong(){
long result = floor(random(0,65536));
for(int i=0;i<3;i++){
result<<= 24;
result+=floor(random(0,16777216));
}
return result;
}
void randomrule(){
RULE[0] = randomlong();
RULE[1] = randomlong();
RULE[2] = randomlong();
RULE[3] = randomlong();
}
void update(){
for (int y=0;y<xyz;y++){
for (int x=0;x<xyz;x++){
rid[x][y].update_pixels();
}}
}
void display(){
updatePixels();
for (int y=0;y<xyz;y++){
for (int x=0;x<xyz;x++){
rid[x][y].buffer();
}}
}
}
class subdivision{
long [] rule;
int [] ra; // results array
int [] val; // value array
int x,y; // coordinate of the pixel
int xy; // x,y in one dimensional framebuffer
int [][] neighbours;
subdivision(int X, int Y, int[]VAL, long[]RULE){
x=X; y=Y; val=VAL; rule=RULE;
xy = x+xyz*y;
neighbours = new int [8][4];
ra = new int [4];
}
void set_neighbours(subdivision[][] rid){
int x1,x3,y1,y3;
for ( int i=0; i < 4; i++) {
x1=(x+1)%xyz; x3=(x+xyz-1)%xyz; // 3 is -1 as it "wraps around"
y1=(y+1)%xyz; y3=(y+xyz-1)%xyz;
// surrounding pixels clockwise
neighbours[ 0] = rid[x1][y3].val;
neighbours[ 1] = rid[x1][ y].val;
neighbours[ 2] = rid[x1][y1].val;
neighbours[ 3] = rid[ x][y1].val;
neighbours[ 4] = rid[x3][y1].val;
neighbours[ 5] = rid[x3][ y].val;
neighbours[ 6] = rid[x3][y3].val;
neighbours[ 7] = rid[ x][y3].val;
}
}
/* Thanks to u/ErasmusDarwin */
int blackbox(long n,long rule){return int((rule>>(n*4))&15);}
int pixel(int foo, int bar) {
if (smooth <= 0){return foo;} else if(smooth >= 8){return bar;} else{
int r,g,b;
r = ( ( (foo >> 16 & 0xFF) * ((1 << smooth) -1) + (bar >> 16 & 0xFF) ) >> smooth ) << 16;
g = ( ( (foo >> 8 & 0xFF) * ((1 << smooth) -1) + (bar >> 8 & 0xFF) ) >> smooth ) << 8;
b = ( ( (foo & 0xFF) * ((1 << smooth) -1) + (bar & 0xFF) ) >> smooth );
return r+g+b;
}
}
int merge(){
int r,g,b;
r = (((ra[0] >> 16 & 0xFF) + (ra[1] >> 16 & 0xFF) + (ra[2] >> 16 & 0xFF) + (ra[3] >> 16 & 0xFF)) >> 2) << 16;
g = (((ra[0] >> 8 & 0xFF) + (ra[1] >> 8 & 0xFF) + (ra[2] >> 8 & 0xFF) + (ra[3] >> 8 & 0xFF)) >> 2) << 8;
b = ((ra[0] & 0xFF) + (ra[1] & 0xFF) + (ra[2] & 0xFF) + (ra[3] & 0xFF)) >> 2;
return #000000+r+g+b;
}
void update_pixels() {
dis=floor(dist(mouseX,mouseY,x,y));
int c; // comparission
int t; // transformation
int r; // result
int top, bottom, layer; //
for (int l=0; l<4; l++){
if(mousePressed) {
smooth = max(0,min(8,dis >> 6));
} else {
smooth=0;
}
if(mousePressed && dis<1+speed) {
r = paint;
} else {
top = (l+1)%4; bottom=(l+3)%4;
c=0;
for (int n=0; n<8; n++){
if ( val[l] > neighbours[ n][top] ) {c++;}
if ( val[l] > neighbours[ n][bottom] ) {c++;}
}
t=blackbox(c,rule[l]);
if (t<=7){ layer = top; } else { t-=8; layer=bottom; }
r=neighbours[t][layer];
}
ra[l]=pixel(r,val[l]);
}
pixels[xy] = merge();
}
void buffer() {
for (int l=0; l<4; l++) {
val[l]=ra[l];
}
}
}
Original version
/* Thanks to u/ErasmusDarwin for map function*/
//int rule_map(int n,int rule){return(rule>>(n*2))&3;} 4^4, rules 2^8
//int rule_map(int n,int rule){return int((rule>>(n*3))&7);} 8^8, rules 2^24
int rule_map(long n,long rule){return int((rule>>(n*4))&15);} // 16^16, 2^64 rules
void rla(){
for(int i=0;i<4;i++){
rule[i]=randomlong();
}
}
long randomlong(){
long result = floor(random(0,65536));
for(int i=0;i<3;i++){
result<<= 24;
result+=floor(random(0,16777216));
}
return result;
}
int rlac,smooth = 1;
class gray { gray(){}
int pixel(int[]ca) {
if (smooth == 0){return ca[3];} else{
int r,g,b;
r = ( ( (ca[3] >> 16 & 0xFF) * ((1 << smooth) -1) + (ca[0] >> 16 & 0xFF) ) >> smooth ) << 16;
g = ( ( (ca[3] >> 8 & 0xFF) * ((1 << smooth) -1) + (ca[0] >> 8 & 0xFF) ) >> smooth ) << 8;
b = ( ( (ca[3] & 0xFF) * ((1 << smooth) -1) + (ca[0] & 0xFF) ) >> smooth );
return r+g+b;
}
}
int merge(int[]ca) {
int r,g,b;
r = (((ca[0] >> 16 & 0xFF) + (ca[1] >> 16 & 0xFF) + (ca[2] >> 16 & 0xFF) + (ca[3] >> 16 & 0xFF)) >> 2) << 16;
g = (((ca[0] >> 8 & 0xFF) + (ca[1] >> 8 & 0xFF) + (ca[2] >> 8 & 0xFF) + (ca[3] >> 8 & 0xFF)) >> 2) << 8;
b = ((ca[0] & 0xFF) + (ca[1] & 0xFF) + (ca[2] & 0xFF) + (ca[3] & 0xFF)) >> 2;
return r+g+b;
}
}
gray gs = new gray();
int randomcolor(){return floor(random(0x0,0xffffff));}
int paint = 0x0;
int swap,cc,xyz=256;
long[] rule = new long [4];
int[][][][] fields = new int[2][4][xyz][xyz];
int[]ca=new int[4];
int[]aa=new int[4];
void clear() {
for(int b=0;b<2;b++){
for(int d=0;d<4;d++){
for (int x=0;x < xyz; x++) {
for (int y = 0; y < xyz; y++) {
fields[b][d][x][y] = #ffffff;}}}}}
int algorithm(int d,int x0,int y0){
int dis=floor(dist(mouseX,mouseY,x0,y0));
int speed=floor(dist(pmouseX,pmouseY,mouseX,mouseY));
int [][]n1=fields[swap][(d+4+1)%4];
int [][]n2=fields[swap][(d+4+3)%4];
int m=fields[swap][d][x0][y0];
aa[0]=aa[1]=aa[2]=aa[3]=m & 0xfffffe;
if(mousePressed){
if(dis<1+speed){if(mouseButton==LEFT){return paint;}else{return 0xffffff;}}
smooth=max(0,min(8,dis >> 6));
} else{smooth=0;}
int t=0*0;
int y1=(y0+1)%xyz,y3=(y0+xyz-1)%xyz,
x1=(x0+1)%xyz,x3=(x0+xyz-1)%xyz;
int c = max(0,(((m>n1[x0][y0])?1:0)+
((m>n1[x0][y1])?1:0)+
((m>n1[x0][y3])?1:0)+
((m>n1[x1][y0])?1:0)+
((m>n1[x3][y0])?1:0)+
((m>n2[x0][y0])?1:0)+
((m>n2[x0][y1])?1:0)+
((m>n2[x0][y3])?1:0)+
((m>n2[x1][y0])?1:0)+
((m>n2[x3][y0])?1:0))-1);
switch((rule_map(c,rule[d]))%16){
case 0:t= n1[x0][y1];break;
case 1:t= n1[x0][y3];break;
case 2:t= n1[x1][y0];break;
case 3:t= n1[x3][y0];break;
case 4:t= n1[x1][y1];break;
case 5:t= n1[x3][y3];break;
case 6:t= n1[x3][y1];break;
case 7:t= n1[x1][y3];break;
case 8:t= n2[x0][y1];break;
case 9:t= n2[x0][y3];break;
case 10:t= n2[x1][y0];break;
case 11:t= n2[x3][y0];break;
case 12:t= n2[x1][y1];break;
case 13:t= n2[x3][y3];break;
case 14:t= n2[x3][y1];break;
case 15:t= n2[x1][y3];break;
default:break;}
aa[3]=t;
return gs.pixel(aa);
}
void setup(){size(256,256,P2D);rla();clear();loadPixels();}
void draw() { for (int x=0;x<xyz;x++){
for (int y=0;y<xyz;y++){
for (int d=0;d<4;d++){
fields[(swap+1)%2][d][x][y]=ca[d]=algorithm(d,x,y);
if(d==3){pixels[x+xyz*y]=gs.merge(ca);}}}
} updatePixels(); paint = randomcolor();
if(swap==0){swap=1;}else{swap=0;}
if(rlac++%100==0){rla();}
}
Well, Wolfram is a key thinker in the history of CA -- it is definitely worth a look, even if you don't read books. More specific to Processing, Shiffman devotes a chapter of his Processing book "The Nature of Code" to cellular automata -- you can check out the online copy and examples here:
If you continue working on this project, this might be of interest: Wolfram wrote a controversial (but much, much less crank-ish than DraftScience) book called called A New Kind of Science (2002) on the idea that many aspects of the physical universe might be modeled as cellular automata.
I intend to work on it, but I need to put more thought into it before I continue,
I got a couple sketches of gravity and some UI-stuff that I jump back and forth between as I'm hitting roadblocks, as I'm learning how to code while working on them.
And thanks, I saw his ted talk but don't read books.
It was pretty interesting and took some ideas from it like using rules,
didn't feel like re-coding it though.
Interesting sketch -- thanks for sharing!
If you continue working on this project, this might be of interest: Wolfram wrote a controversial (but much, much less crank-ish than DraftScience) book called called A New Kind of Science (2002) on the idea that many aspects of the physical universe might be modeled as cellular automata.
First attempt at automata,
EDIT: I was a bit too eager to share before it was finnished.
Removed the open processing sketch since it didn't like the jenkins hash functions for generating "rules" https://en.wikipedia.org/wiki/Jenkins_hash_function which is a pretty essential thing.
Here's the code though it should just be copy-pasteable, if you have processing running.
Right click to generate a random pattern.
Cycle "rule" with mouseclick or hardcode int rule =2; to something else as startingpoint, most rules looks same and like shit though.
Planning on doing a better algorithm.
int x = 200;
int y = 200;
int rule = 2;
int[][][][] fields = new int[2][4][x][y];
boolean swap;
void drandomize() {
for (int k = 0; k < 2; k++) {
for (int l = 0; l < 4; l++) {
for (int i = 0; i < x; i++) {
for (int j = 0; j < y; j++) {
fields[k][l][i][j] = int(random(#000000, #ffffff));
}
}
}
}
}
void setup() {
size(200, 200);
drandomize();
loadPixels();
}
int jenkins(long k) {
long hash = rule;
hash += k;
hash += hash << 10;
hash ^= hash >> 6;
hash += hash << 3;
hash ^= hash >> 11;
hash += hash << 15;
return int(hash%8);
}
int algorithm(int d, int i, int j) {
int hue = 0;
int me = fields[(swap)?1:0][(d+4+0)%4][(i+x-1)%x][(j+y+0)%y] ;
int c = // _ _ _
((me < fields[(swap)?1:0][(d+4+1)%4][(i+x+0)%x][(j+y+0)%y]) ? 1:0) +
((me < fields[(swap)?1:0][(d+4+1)%4][(i+x+0)%x][(j+y+1)%y]) ? 1:0) +
((me < fields[(swap)?1:0][(d+4+1)%4][(i+x+1)%x][(j+y+0)%y]) ? 1:0) +
((me < fields[(swap)?1:0][(d+4+1)%4][(i+x+1)%x][(j+y+1)%y]) ? 1:0) +
((me < fields[(swap)?1:0][(d+4-1)%4][(i+x+0)%x][(j+y-0)%y]) ? 1:0) +
((me < fields[(swap)?1:0][(d+4-1)%4][(i+x+0)%x][(j+y-1)%y]) ? 1:0) +
((me < fields[(swap)?1:0][(d+4-1)%4][(i+x-1)%x][(j+y+0)%y]) ? 1:0) +
((me < fields[(swap)?1:0][(d+4-1)%4][(i+x-1)%x][(j+y-1)%y]) ? 1:0);
switch(jenkins(c)) {// _ _ _
case 0: return fields[(swap)?1:0][(d+4+1)%4][(i+x+0)%x][(j+y+0)%x];
case 1: return fields[(swap)?1:0][(d+4+1)%4][(i+x+0)%x][(j+y+1)%x];
case 2: return fields[(swap)?1:0][(d+4+1)%4][(i+x+1)%x][(j+y+0)%x];
case 3: return fields[(swap)?1:0][(d+4+1)%4][(i+x+1)%x][(j+y+1)%x];
case 4: return fields[(swap)?1:0][(d+4-1)%4][(i+x-0)%x][(j+y-0)%x];
case 5: return fields[(swap)?1:0][(d+4-1)%4][(i+x+0)%x][(j+y-1)%x];
case 6: return fields[(swap)?1:0][(d+4-1)%4][(i+x-1)%x][(j+y+0)%x];
case 7: return fields[(swap)?1:0][(d+4-1)%4][(i+x-1)%x][(j+y-1)%x];
default: return #000000;
}
}
void draw() {
for (int d = 0; d < 4; d++) {
for (int i = 0; i < x; i++) {
for (int j = 0; j < y; j++) {
fields[(swap)?0:1][d][i][j] = algorithm(d, i, j); //viewport+1+d)%4
if(d==0){pixels[i+x*j] = fields[(swap)?0:1][0][i][j];}
}
}
if (swap) {swap=false;} else {swap=true;}
background(0);
updatePixels();
fill(255); textSize(40);
text("#"+str(rule),80,105);
}
}
void mouseClicked(){
if (mouseButton == LEFT ) { rule++; println(rule);}
else if (mouseButton == RIGHT) { drandomize(); }
}
The "math" is pretty much just +1 -1 but the structure is a bit messy.
The "fields" of pixels, (not using any vectors) start up randomized in setup and follow the "algorithm" from there.
It seems to be able to do some trippy looking stuff, although it seems to be repeating patterns and the randomness just just coming from the random setup. And this first sketch is mostly just for practicing using arrays and drawing pixels on screen.
But I have an idea about the arrows thing, I'll be drawing them in inkscape and trying to think of "my own" rules rather than trying to follow draft sciences, for how to make patterns. Its very unclear what happens when for example 3 arrows converge and there seems to be many different ways you can concieve of them going. Probably the best approach is to let the computer brute force through all possible variations. And i kind of think of them as just "neighbour relations" of points in a field rather than vectors. And by fields I just mean "numbers in space".
I think I'll use 12 fields, 4*3 for x-y and rgb , and maybe need another dimension, maybe its very wasteful but I haven't figured out the details yet I am going to draw a plan.
I think you've put your finger on the problem.
Contra all those sketches, at first glance I don'e see how one could get cellular automata to generate circular orbiting structures ex nihilo by just bumping vector values into each other. There would have to be higher rules in the code reflecting the "all-of-the-rest-of-physics" that DraftScience hides in statements like "It is a quality of the physical universe which enables such patterns to become durable that is responsible for all that we know as matter."
If you are interested in playing around with rendering systems of arrows and/or cellular automata and flocking, some recent posts that might be interesting:
rendering a field of arrows:
particle field project:
past discussions of CA:
I'm using processing/ just java, afaik that thread is about 2d array iteration with one or two properties, relevance? i also have no idea what your code is doing in any of those posts.
I've made loads of different automata sketches in the past with no issues. My question here is about how to organise a sketch in the aforementioned specific situation.
Anyway I get the general message, I need to be more clever and read up more on how to structure my sketches, only post in forum with more specific/ concrete query
I see -- this doesn't really have anything to do with the Game of Life or with cellular automata, then.
Happy to help!
Here is the formula for a Fibonacci sequence described on "Math is Fun":
So we can write the rule:
The Rule is xn = xn-1 + xn-2
Once you calculate it, you can show text (such as a number) on the screen using the function:
Try to make this sketch and then share it. If you have problems, share your properly formatted source code here and ask specific questions for feedback on how to make it work.
Simple answer here is to make OOP grid. Have a class for a Cell and a class for a Grid. You can then create a system that will return you a reference for particular cell and you will be able to manipulate it. I recommend "Nature of code" by Shiffman, particulary, there's a chapter explaining grids in detail: http://natureofcode.com/book/chapter-7-cellular-automata/ If this would seem too hard, start the book from the beginning.
Hi. I am very new to processing, and currently I am doing some exploration on 3D Cellular Automata. Basically, I followed the tutorial of Cellular Automata by Jose Sanchez ( in 2d) and I am trying to edit the codes into 3d. The first intention is to make the cell grows in the z-axis. I tried a few times, and I did not manage to do it. So in the end I chose to make the whole thing as a box, and have the activity of cells inside the box. But I failed. I have no idea what's the problem with my codes. Could anyone help me please?
Below is the code:
import peasy.*;
import toxi.geom.*;
PeasyCam cam;
int generations;
int cols = 50; // population
int rows = 50;
int depth = 50;
CA [][][] grid = new CA [cols][rows][depth]; //declare two dimmensional array
void setup () {
size(1280, 720, P3D);
frameRate (12);
generations = 0;
cam = new PeasyCam (this, 100);
for (int i = 0; i < cols; i++) {
for (int j = 0; j < rows; j++) {
for ( int k = 0; k < depth; k++) {
Vec3D ptLoc = new Vec3D ( i* 10, j * 10, k*10);
grid [i][j][k] = new CA (ptLoc, i, j, k, 3, 0.8);
}
}
}
}
void draw () {
background (0);
stroke (255);
generations++;
rotateX(radians(45));
rotateZ(radians(45));
fill(255);
cam.beginHUD();
text("Generations: "+generations, width-150, height-20);
cam.endHUD();
// rect (0,0,600,600);
for (int i = 0; i < cols; i++) {
for (int j = 0; j < rows; j++) {
for ( int k = 0; k < depth; k++) {
grid[i][j][k].run();
}
}
}
for (int i = 0; i < cols; i++) {
for (int j = 0; j < rows; j++) {
for ( int k = 0; k < depth; k++) {
grid[i][j][k].updateType();
grid[i][j][k].loc.z = grid[i][j][k].loc.z ;
}
}
}
}
////////////////////////////////////////////////// CLASS CA
class CA {
Vec3D loc;
int x;
int y;
int z;
float density = 0.8;
int sz = 3;
int [][][][] world;
//specify your neighbour
int type = 0;
int futType = 100;
CA(Vec3D _loc, int _x, int _y, int _z, int _sz, float _density) {
loc = _loc;
x = _x;
y = _y;
z = _z;
density = _density;
sz = _sz;
world = new int [x][y][z][2];
for (int i = 0; i < density*x*y*z; i+=sz ) {
for (int j = 0; j < density*x*y*z; j+=sz ) {
for (int k = 0; k < density*x*y*z; k+=sz ) {
world [( int ) random (x)] [( int ) random (y)] [( int ) random (z)] [0] = 1;
// float rnd = random (100);
// if (rnd < 50) {
// type = 1;
//}
}
}
}
}
void run() {
display();
evo1N();
}
void updateType() {
type = futType;
}
void evo1N() {
int count = 0;
if ( grid [(x+cols-1)%cols] [(y+rows-1)%rows ] [(z+depth+1) %depth].type == 1) count ++;
if ( grid [(x+cols)%cols] [(y+rows-1)%rows] [(z+depth-1) %depth].type == 1) count ++;
if ( grid [(x+cols+1)%cols] [(y+rows-1)%rows] [(z+depth) %depth].type == 1) count ++;
if ( grid [(x+cols-1)%cols] [(y+rows)%rows] [(z+depth-1) %depth].type == 1) count ++;
if ( grid [(x+cols+1)%cols] [(y+rows)%rows] [(z+depth) %depth].type == 1) count ++;
if ( grid [(x+cols-1)%cols] [(y+rows+1)%rows] [(z+depth) %depth].type == 1) count ++;
if ( grid [(x+cols)%cols] [(y+rows+1)%rows] [(z+depth+1) %depth].type == 1) count ++;
if ( grid [(x+cols+1)%cols] [(y+rows+1)%rows] [(z+depth+1) %depth].type == 1) count ++;
//if i have too many neighbours around me, i die out of the over population
if (type == 1 && count < 2) {
futType = 0;
}
if (type == 1 && count <=3 && count >=2) {
futType = 1;
}
if (type ==1 && count > 3) {
futType = 0;
}
if (type == 0 && count == 3) {
futType = 1;
}
}
void display () {
if (type == 1) {
stroke (255);
pushMatrix ();
translate ( cols, rows, depth );
box ( sz );
popMatrix ();
strokeWeight ( 2 );
point (loc.x, loc.y, loc.z);
}
}
}
Thank you.