git @ Cat's Eye Technologies Rigamaroads / master src / rigamaroads.js
master

Tree @master (Download .tar.gz)

rigamaroads.js @masterraw · history · blame

// SPDX-FileCopyrightText: Chris Pressey, the creator of this work, has dedicated it to the public domain.
// For more information, please refer to <https://unlicense.org/>
// SPDX-License-Identifier: Unlicense

var GRID_WIDTH = 40;
var GRID_HEIGHT = 40;
var CELL_WIDTH = 20;
var CELL_HEIGHT = 20;

var QUADRANT = Math.PI / 2;


Rigamaroads = function() {
    this.init = function(cfg) {
        this.canvas = cfg.canvas;
        this.ctx = this.canvas.getContext('2d');
        this.reset();
    };

    this.reset = function() {
        this.playfield = new Array(GRID_WIDTH);
        var x;
        for (x = 0; x < GRID_WIDTH; x++) {
            this.playfield[x] = new Array(GRID_HEIGHT);
        }

        var freeSpots = [];
        for (var x = 0; x < GRID_WIDTH; x++) {
            for (var y = 0; y < GRID_HEIGHT; y++) {
                freeSpots.push([x, y]);
            }
        }
        this.freeSpots = freeSpots;
        this.go();
    };

    this.go = function() {
        if (this.interval) {
            clearInterval(this.interval);
        }
        var $this = this;
        this.interval = setInterval(function() {
            $this.update();
            $this.draw();
        }, 10);
    };

    this.pickFor = function(x, y) {
        var pf = this.playfield;

        // assert(pf.get(x, y) === undefined);

        var get = function (a, x, y) {
            var col = a[x];
            if (col === undefined) return undefined;
            return col[y];
        }
        var north = get(pf, x, y - 1) || 'XXXX';
        var east = get(pf, x + 1, y) || 'XXXX';
        var south = get(pf, x, y + 1) || 'XXXX';
        var west = get(pf, x - 1, y) || 'XXXX';

        var connector = function(c) {
            if (c === '1') return '1';
            if (c === '0') return '0';
            if (c === 'X') return Math.random() > 0.75 ? "1" : "0";
        };

        return (
            connector(north.charAt(2)) +
            connector(east.charAt(3)) +
            connector(south.charAt(0)) +
            connector(west.charAt(1))
        );
    };

    this.plunkIntoFreeSpot = function() {
        var pos = Math.trunc(Math.random() * this.freeSpots.length);
        var spot = this.freeSpots.splice(pos, 1)[0];
        if (spot === undefined) {
            return false;  // we're done
        }
        var x = spot[0];
        var y = spot[1];

        var countConnections = function(s) {
            var count = 0;
            for (var i = 0; i < s.length; i++) {
                if (s.charAt(i) === '1') count++;
            }
            return count;
        };

        var pick;
        for (var i = 0; i < 10; i++) {
            pick = this.pickFor(x, y);
            if (countConnections(pick) > 1) break;
        }

        this.playfield[x][y] = pick;

        return true;
    };

    this.update = function() {
        for (var i = 0; i < 10; i++) {
            var plunked = this.plunkIntoFreeSpot();
            if (!plunked) {
                this.draw();
                clearInterval(this.interval);
                return;
            }
        }
    };

    this.draw = function() {
        var x, y;
        for (x = 0; x < GRID_WIDTH; x++) {
            for (y = 0; y < GRID_HEIGHT; y++) {
                this.drawCell(this.playfield[x][y] || 'XXXX', x, y);
            }
        }
    };

    // NESW convention.
    // 1111 = +, 0000 = space
    // 1 = we have a connection in that direction
    // 0 = we don't
    // X = we haven't decided yet
    this.drawCell = function(value, playfieldX, playfieldY) {
        var cellWidth = CELL_WIDTH;
        var cellHeight = CELL_HEIGHT;
        canvasX = playfieldX * cellWidth;
        canvasY = playfieldY * cellHeight;

        var cx; var cy; var q1; var q2;
        var drawArc = false;

        var ctx = this.ctx;

        if (value === '1100') {
            cx = canvasX + cellWidth;
            cy = canvasY;
            q1 = 1;
            q2 = 2;
            drawArc = true;
        } else if (value === '0110') {
            cx = canvasX + cellWidth;
            cy = canvasY + cellHeight;
            q1 = 2;
            q2 = 3;
            drawArc = true;
        } else if (value === '0011') {
            cx = canvasX;
            cy = canvasY + cellHeight;
            q1 = 3;
            q2 = 4;
            drawArc = true;
        } else if (value === '1001') {
            cx = canvasX;
            cy = canvasY;
            q1 = 4;
            q2 = 5;
            drawArc = true;
        } else {
            ctx.fillStyle = 'black';
            ctx.fillRect(canvasX, canvasY, cellWidth, cellHeight);
            ctx.strokeStyle = 'yellow';
            ctx.lineWidth = 4;

            if (value.charAt(0) === '1') {
                ctx.beginPath();
                ctx.moveTo(canvasX + cellWidth / 2, canvasY);
                ctx.lineTo(canvasX + cellWidth / 2, canvasY + cellHeight / 2);
                ctx.stroke();
            }
            if (value.charAt(1) === '1') {
                ctx.beginPath();
                ctx.moveTo(canvasX + cellWidth,     canvasY + cellHeight / 2);
                ctx.lineTo(canvasX + cellWidth / 2, canvasY + cellHeight / 2);
                ctx.stroke();
            }
            if (value.charAt(2) === '1') {
                ctx.beginPath();
                ctx.moveTo(canvasX + cellWidth / 2, canvasY + cellHeight);
                ctx.lineTo(canvasX + cellWidth / 2, canvasY + cellHeight / 2);
                ctx.stroke();
            }
            if (value.charAt(3) === '1') {
                ctx.beginPath();
                ctx.moveTo(canvasX,                 canvasY + cellHeight / 2);
                ctx.lineTo(canvasX + cellWidth / 2, canvasY + cellHeight / 2);
                ctx.stroke();
            }

            if (value === '1000' || value === '0100' || value === '0010' || value === '0001') {
                /*
                ctx.beginPath();
                ctx.fillStyle = Math.random() > 0.5 ? "orange" : "red";
                ctx.arc(canvasX + cellWidth / 2, canvasY + cellHeight / 2, cellHeight / 4, 0, 2 * Math.PI, false);
                ctx.fill();
                */
                ctx.beginPath();
                ctx.fillStyle = 'black';
                ctx.strokeStyle = 'yellow';
                ctx.lineWidth = 4;
                ctx.arc(canvasX + cellWidth / 2, canvasY + cellHeight / 2, cellHeight / 4, 0, 2 * Math.PI, false);
                ctx.fill();
                ctx.stroke();
            }
        }
        
        if (drawArc) {
            ctx.fillStyle = 'black';
            ctx.fillRect(canvasX, canvasY, cellWidth, cellHeight);
            ctx.strokeStyle = 'yellow';
            ctx.lineWidth = 4;

            ctx.beginPath();
            var r = cellWidth / 2;
            ctx.arc(cx, cy, r, QUADRANT * q1, QUADRANT * q2, false);
            ctx.stroke();
        }
    };
}