function decodeCanon(apgcode) {

    var i;
    var chars = "0123456789abcdefghijklmnopqrstuvwxyz"

    for (i = 0; i < apgcode.length; i++) {
        if (apgcode[i] == "_") {
            i += 1;
            break;
        }
    }
    
    var blank = 0;
    var x = 0;
    var y = 0;
    var plane = 0;
    var cells = []
    
    for (/**/; i < apgcode.length; i++) {
   
        var c = apgcode[i];
        if (blank) {
            x += chars.indexOf(c);
            blank = 0;
        } else if (c == 'y') {
            x += 4;
            blank = 1;
        } else if (c == 'x') {
            x += 3;
        } else if (c == 'w') {
            x += 2;
        } else if (c == 'z') {
            x = 0;
            y += 5;
        } else if (c == '_') {
            x = 0;
            y = 0;
            plane += 1;
        } else {
            v = chars.indexOf(c);
            for (var j = 0; j < 5; j++)
                if (v & (1 << j)) {
                    cells.push(x);
                    cells.push(y+j);
                    cells.push(plane);
                }
            x += 1;
        }
    }

    return cells;
}

function add_symbol(out_pair, num, symbol) {
    if (num == 0) return;
    if (num > 1) symbol = num.toString() + symbol;
    out_pair[1] += symbol.length;
    if (out_pair[1] > 77) {
        out_pair[0] += "<br>";
        out_pair[1] = symbol.length;
    }
    out_pair[0] += symbol;
}

function state2string(c, maxplane) {
    if (c == 0) {
        if (maxplane == 0) {
            return "b";
        } else {
            return ".";
        }
    } else if (c == 1) {
        if (maxplane == 0) {
            return "o";
        } else {
            return "A";
        }
    } else {
        var d = c - 1;
        var a = String.fromCharCode(65 + (d % 24));
        d = Math.floor(d / 24);
        while (d > 0) {
            a = String.fromCharCode(112 + ((d + 10) % 11)) + a;
            d = Math.floor(d / 11);
        }
        return a;
    }
}

function cells_to_rle(cells, rulestring) {

    if (cells.length == 0) return ("x = 0, y = 0, rule = " + rulestring + "<br>!");

    var minx = 99999;
    var maxx = -99999;
    var miny = 99999;
    var maxy = -99999;

    var maxplane = cells[cells.length - 1];

    for (var i = 0; i < cells.length; i += 3) {

        x = cells[i];
        y = cells[i+1];

        if (x > maxx) maxx = x;
        if (x < minx) minx = x;
        if (y > maxy) maxy = y;
        if (y < miny) miny = y;

    }

    var pairs = [];
    for (var i = 0; i < cells.length; i += 3)
        pairs.push(cells[i+2] + 64 * (cells[i]-minx) + 65536 * cells[i+1]);
    pairs.sort(function(a,b){return a-b});

    var lastci = -1;
    var cc = 0;

    cells = []
    pairs.push(-1);

    for (var i = 0; i < pairs.length; i++) {

        var currci = (pairs[i] >> 6);

        if (lastci != currci) {
            if (lastci != -1) {
                cells.push(lastci & 1023);
                cells.push(lastci >> 10);
                cells.push(cc);
            }
            lastci = currci;
            cc = 0;
        }

        cc += (1 << (pairs[i] & 63));
    }

    var w = maxx - minx + 1;
    var h = maxy - miny + 1;
    var output = "x = " + w.toString() + ", y = " + h.toString() + ", rule = " + rulestring + "<br>";
    var out_pair = [output, 0];

    var lastx = 0; var lasty = 0; var lastc = 0;
    var runlength = 0;

    var ruleparts = rulestring.split("/");
    var statestring = "";

    if (ruleparts.length == 3) {
        statestring = ruleparts[2];
    } else {
        var ruleparts2 = rulestring.split(",C");
        if (ruleparts2.length == 2) {
            statestring = ruleparts2[1].split(",")[0];
        }
    }

    var gstates = 0;

    if ( /^([1-9][0-9]*)$/.test(statestring)) {
        gstates = parseInt(statestring);
    }

    for (var i = 0; i < cells.length; i += 3) {

        var x = cells[i];
        var y = cells[i+1];
        var c = cells[i+2];

        if ((gstates > 0) && (c > 1)) {
            c = gstates - 1 - (c >> 2);
        }

        if ((y > lasty) || (x > lastx) || (c != lastc)) {

            add_symbol(out_pair, runlength, state2string(lastc, maxplane));
            if (y > lasty) {
                add_symbol(out_pair, y - lasty, "$");
                lasty = y;
                lastx = 0;
            }
            if (x > lastx) {
                add_symbol(out_pair, x - lastx, state2string(0, maxplane));
            }
            runlength = 0;
        }
        runlength += 1;
        lastx = x + 1;
        lastc = c;
    }

    add_symbol(out_pair, runlength, state2string(lastc, maxplane));

    return out_pair[0] + "!";
    
}

example = "xp3_4hh186z07"
cells = cells_to_rle(decodeCanon(example), "B3/S23");
console.log(cells)

Embed on website

To embed this program on your website, copy the following code and paste it into your website's HTML: