Life Missile Command

Shooting gliders at incoming spaceships!

Log in to post a comment.

Canvas.setpenopacity(-0.05);

const gridSize = 100;
const steps = 720;

const GLIDER = [
    [0, 1, 0],
    [1, 0, 0],
    [1, 1, 1],
]
const LWSS = [
    [0, 0, 1, 1, 0],
    [1, 1, 0, 1, 1],
    [1, 1, 1, 1, 0],
    [0, 1, 1, 0, 0],
]
const MWSS = [
    [0, 0, 0, 1, 1, 0],
    [1, 1, 1, 0, 1, 1],
    [1, 1, 1, 1, 1, 0],
    [0, 1, 1, 1, 0, 0],
]
const HWSS = [
    [0, 0, 0, 0, 1, 1, 0],
    [1, 1, 1, 1, 0, 1, 1],
    [1, 1, 1, 1, 1, 1, 0],
    [0, 1, 1, 1, 1, 0, 0],
]

const patterns = [{
    pattern: LWSS,
    x: 0,
    y: 15,
},{
    pattern: LWSS,
    x: 0,
    y: 72,
},{
    pattern: MWSS,
    x: 0,
    y: 62,
},{
    pattern: MWSS,
    x: 0,
    y: 35,
},{
    pattern: MWSS,
    x: 0,
    y: 55,
},{
    pattern: HWSS,
    x: 0,
    y: 85,
}];

const launchPatterns = [{
    pattern: GLIDER,
    x: 50,
    dx: 50,
    y: 0,
    every: 25,
}]

const applyPattern = (pattern, onto, lx, ly) => {
    for (let y = 0; y<pattern.length; y++) {
        for (let x = 0; x<pattern[y].length; x++) {
            onto[ly+y][lx+x] = Boolean(pattern[y][x]);
        }
    }
}

const applyPatterns = (patterns, onto) => {
    for (const { pattern, x: lx, y: ly } of patterns) {
        applyPattern(pattern, onto, lx, ly);
    }
}

// No fancy-pants bit-juggling here, we do a whole lotta lookups!
let generation = new Array(gridSize).fill(0).map(y => new Array(gridSize).fill(0).map(x => false));
applyPatterns(patterns, generation)

const cellSize = (200/gridSize);
const turtle = new Turtle();
turtle.seth(0);

function walk(i) {
    for (let y = 0; y < gridSize; y++) {
        for (let x = 0; x < gridSize; x++) {
            if (generation[y][x]) draw(x+1, y+1);
        }
    }
    generation = generation.map((y, yi, ys) => {
        return y.map((x, xi, xs) => {
            const n = countNeighbours(xi, yi, generation);
            if (x && n > 1 && n < 4) return true;
            else if (n === 3) return true;
            return false;
        })
    });
    for (const { pattern, x, dx = 0, y, every } of launchPatterns) {
        if (i > 0 && i%every===0) {
            applyPattern(pattern, generation, Math.floor(x-dx+2*dx*Math.random()), y);
        }
    }

    return i < steps;
}

const countNeighbours = (xi, yi, ys) => {
    const xs = ys[yi];
    const li = xi === 0 ? xs.length-1 : xi-1;
    const l = xs[li];
    const ri = xi === xs.length-1 ? 0 : xi+1;
    const r = xs[ri];
    const ti = yi === 0 ? ys.length-1 : yi-1;
    const t = ys[ti][xi];
    const bi = yi === ys.length-1 ? 0 : yi+1;
    const b = ys[bi][xi];
    const tl = ys[ti][li];
    const bl = ys[bi][li];
    const br = ys[bi][ri];
    const tr = ys[ti][ri];
    return [l, r, t, b, tl, bl, br, tr].reduce((count, i) => i ? count + 1 : count, 0);
}

const draw = (_x, _y) => {
    const x = -100 + cellSize * _x;
    const y = -100 + cellSize * _y;
    for (let i = 0; i<cellSize-0.1; i+=0.25) {
        turtle.jump(-x, -y+i);
        turtle.forward(cellSize);
    }
}