Conway's Game Of Life in BlinkScript (because why not)

I’ve finally started toying around with BlinkScript. After multiple unsuccessful attempts at understanding the Blink Reference Guide, I am now faced with an interesting enough challenge that I went back to it, for real. I’ve also started working with Guillem Ramisa De Soto, which, to be honest, feels like a huge cheat code (i r winner).

I’m not too far on my journey to mastering the power of the node, but I’m at least confident that I now understand the language well enough to work with it.

So, when I watched Veritasium’s video about math being flawed this weekend, I naturally had to try making Conway’s Game Of Life in BlinkScript.
And so, here it is:

The Setup

feedback_loop_screenshot.png

The main problem of Conway’s Game Of Life is that you need to know the current state of the cell at t to generate the next cells at t+1. On it’s own, that’s perfectly reasonable but you can’t really do that in Nuke. So, I had to render each frame to feed them back to the script via a time offsetted read, thus creating a feedback loop.

The comp looks like that.

Feedback loop logic

  • At frame == 1

    • Render Frame 1

  • At frame >= 2

    • Load frame-1 via the read and the framehold [frame-1] nodes

    • Go through the BlinkScript Node to get the state of the game at frame based on the state of the game at frame-1

    • Render it and start again for frame+1

The Code

kernel TheGameOfLife : public ImageComputationKernel
{
    Image src; 
    Image dst;

    param:
        // Color above which a pixel will be consider as alive
        float whitePoint;

    void init()
    {
        // To get the neighbouring pixels
        src.setRange(-1, -1, 1, 1);
    }

    void process(int2 pos)
    {

        float neighbours[9];
        int neighboursCount = 0;

        // Loop on every pixels neighbouring the current one
        int index = 0;
        for (int i = -1; i <= 1; i++) {
            for (int j = -1; j <= 1; j++) {
                neighbours[index] = src(i, j);
                index += 1;
            }
        }
        // Neighbouring pixel coordinates
        // (-1,  1) - (0,  1) - (1,  1)
        // (-1,  0) - (0,  0) - (1,  0)
        // (-1, -1) - (0, -1) - (1, -1)

        // Count the number of neighbouring pixels that are alive
        // Do not count the current pixel to avoid self reference and messed up results
        for (int i = 0; i <= 9; i++) {
            if (i != 4) {
                if (neighbours[i] > whitePoint) {
                    neighboursCount += 1;
                }
            }
        }

        // Output based on the rules of the game
        dst() = 0.0f;

        // Current is alive
        if (neighbours[4] > whitePoint) {
            if (neighboursCount > 3) {
                // Any live cell with more than three live neighbours dies, as if by overpopulation.
                dst() = 0.0f;
            } else if (neighboursCount >= 2) {
                // Any live cell with two or three live neighbours lives on to the next generation.
                dst() = 1.0f;
            } else if (neighboursCount < 2) {
                // Any live cell with fewer than two live neighbours dies, as if by underpopulation.
                dst() = 0.0f;
            }
        // Current is dead
        } else {
            if (neighboursCount == 3) {
                // Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction.
                dst() = 1.0f;
            }
        }
    }
};

Have fun with it !