.), east movers (>), and south movers (v). Each step, move all east movers than all south movers (only if they can this iteration). Wrap east/west and north/south. How many steps does it take the movers to get stuck?Okay. A random post on the /r/cellular_automata subreddit inspired me.
Let’s generate a cellular automata where each pixel updates based on a neural network given as input:
Let’s do it!
L-Systems are pretty awesome. With only a bare few rules, you can turn something like this:
LSystem.new("Barnsley Fern") do
start "+++X"
rule "X", "F+[[X]-X]-F[-FX]+X"
rule "F", "FF"
terminal "F" do forward end
terminal "[" do push end
terminal "]" do pop end
terminal "-" do rotate -25 end
terminal "+" do rotate +25 end
end
Into this:
Let’s make magic circles/runes!
Turn this:
rune do
scale 0.9 do
circle
polygon 7
star 14, 3
star 7, 2
children 7, scale: 1/8r, offset: 1 do |i|
circle
invert do
text (0x2641 + i).chr Encoding::UTF_8
end
end
end
scale 0.15 do
translate x: -2 do circle; moon 0.45 end
circle
translate x: 2 do circle; moon 0.55 end
end
end
Into this:
The fine people of /r/generative / Genuary2021 have a series of challenges for generative works for the month of January. I don’t think I’m going to do all of them, but pick and choose. For example, the very first prompt is:
// TRIPLE NESTED LOOP
My goal was to draw a grid of circles across the X/Y the image and nest them for the third dimension. To make it a little more interesting, I added a few different color modes. seededRandom is my personal favorite, that was interesting to get working.
Much like transpiling register machines, now we have a chance to transpile stack machines. Unfortunately, it doesn’t actually speed up the code nearly so much (the stack is just not as effective of a memory structure in this case), but it’s still an interesting bit of code.
In this case, we turn something like this:
invsub
polT
writeG
id
neg
zero?
sin
invsub
ZERO
inv
Into this:
function(X, Y) {
this.x = X;
this.y = Y;
this.stack = [];
this.r = undefined;
this.g = undefined;
this.b = undefined;
this.stack.push(X);
this.stack.push(Y);
var arg0 = 0;
var arg1 = 0;
var arg2 = 0;
var result = 0;
// invsub
arg0 = this.stack.pop() || 0;
result = 1 - arg0;
result = result % 1.0;
this.stack.push(result);
// polT
arg0 = this.stack.pop() || 0;
arg1 = this.stack.pop() || 0;
result = Math.atan2(arg0, arg1);
result = result % 1.0;
this.stack.push(result);
// writeG
arg0 = this.stack.pop() || 0;
this.g = arg0;
// id
arg0 = this.stack.pop() || 0;
result = arg0;
result = result % 1.0;
this.stack.push(result);
// neg
arg0 = this.stack.pop() || 0;
result = -arg0;
result = result % 1.0;
this.stack.push(result);
// zero?
arg0 = this.stack.pop() || 0;
arg1 = this.stack.pop() || 0;
arg2 = this.stack.pop() || 0;
result = arg0 === 0 ? arg1 : arg2;
result = result % 1.0;
this.stack.push(result);
// sin
arg0 = this.stack.pop() || 0;
result = Math.sin(arg0);
result = result % 1.0;
this.stack.push(result);
// invsub
arg0 = this.stack.pop() || 0;
result = 1 - arg0;
result = result % 1.0;
this.stack.push(result);
// ZERO
result = 0;
result = result % 1.0;
this.stack.push(result);
// inv
arg0 = this.stack.pop() || 0;
result = 1 / arg0;
result = result % 1.0;
this.stack.push(result);
return [
this.r === undefined ? this.stack.pop() || 0 : this.r,
this.g === undefined ? this.stack.pop() || 0 : this.g,
this.b === undefined ? this.stack.pop() || 0 : this.b,
];
}
Okay, enough with register machines. Let’s make something new. This time, a stack based machine!
Rather than keeping it’s memory in a series of memory cells, there will be a single stack of values. All functions can pop values from the top of the stack or push them back on. I will add the ability to read the X/Y value and directly write R/G/B, but you can’t write to the former or read from the latter, so you can’t use them as registers. Let’s see what that looks like!