# Neural Network Cellular Automata

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:

• The x/y coordinates (scaled to the range 0-1)
• An optional random value (to make it more dynamic)
• A variety of neighboring data, such as:
• The number of neighbors that are ‘active’ (> 50% white), ranges 0-8 scaled to 0-1. This should allow Conway's Game of Life
• The RGB values of all neighbors (allows a superset of the above)
• Gradients, subtract color value of the left from the right so that you get edges and side to side movement

Let’s do it!

# Solving Snakebird

Snakebird!

A cute little puzzle game, where you move around snake(birds). Move any number of snakes around the level, eating fruit, and getting to the exit. The main gotchas are that you have gravity to content with–your snake will easily fall off the edge of the world–and each time you eat a fruit, your snake gets bigger. This can help get longer to get into hard to reach places or it can cause trouble when you trap yourself in corners.

Let’s use the new immutable.js solver to solve these problems!

# Immutable.js Solvers

A bit ago I wrote about writing a generic brute force solver (wow, was that really two months ago?). It got … complicate. Mostly, because every time I wrote a step function, I had to be careful to undo the same. Wouldn’t it be nice if we could just write a step function and get backtracking for ‘free’?

Well, with immutability you can!

# A Generic Brute Force Backtracking Solver

One of the projects I’ve had vaguely in the back of my head is a sort of generic puzzle solver. I really love puzzles, but of the pencil and paper and video game varieties. So I think it would be awesome to write out a definition of a puzzle (say how to play Sudoku), give it input, and have it give me an answer back.

Well, I finally got around to trying it!

# GMail Oldest First

It’s been rather a while since I last worked on a userscript, but there’s been a problem I’ve been trying to solve for some time.

I want to have my GMail in order from oldest to newest. While you can do this for all messages, you can’t do it within a single page.

# Genuary: Triple Nested Loops

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.

# Pictogenesis: Stack Transpiling

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,
];
}


# Pictogenesis: Stack Machine

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!

# Pictogenesis: Transpiling

Okay. That is slow… Let’s make it faster!

So the main problem we have is that we’re interpreting the code. For every single pixel, for every line of code, we’re doing a few housekeeping things and making at least one function call. For a 400x400 image with just 10 lines of code, that’s 1.6M function calls. Like I said, slow.

So let’s make it faster!

My first idea? Transpile it to Javascript!

Now that I’ve got register machines working, one of the next ideas I had was to implement different wrapping modes. Currently, as it stands, X and Y are passed into the machine as floating point numbers from [0, 1] across the image and output is expected to be [0, 1] for each of R, G, and B. Any values that end up outside of that range, we truncate down to that range. But some of our mathematical functions (multiplication, exponentiation, negation, etc) tend to generate numbers way out of this range. But they don’t have to!