git @ Cat's Eye Technologies HTML5-Gewgaws / master rigamaroads / rigamaroads.js
master

Tree @master (Download .tar.gz)

rigamaroads.js @masterraw · history · blame

"use strict";

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

var QUADRANT = Math.PI / 2;


function launch(prefix, containerId, config) {
    var config = config || {};
    var deps = [
        "element-factory.js",
        "playfield.js",
        "playfield-canvas-view.js",
        "animation.js"
    ];
    var loaded = 0;
    for (var i = 0; i < deps.length; i++) {
        var elem = document.createElement('script');
        elem.src = prefix + deps[i];
        elem.onload = function() {
            if (++loaded < deps.length) return;
            var container = document.getElementById(containerId);

            var canvas = yoob.makeCanvas(container, GRID_WIDTH * CELL_WIDTH, GRID_HEIGHT * CELL_HEIGHT);

            var gewgaw = (new Rigamaroads()).init({ canvas: canvas });
        };
        document.body.appendChild(elem);
    }
}


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

        this.playfield = (new yoob.Playfield()).init({});

        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.canvasView = (new yoob.PlayfieldCanvasView()).init({
            playfield: this.playfield,
            canvas: this.canvas,
            cellWidth: CELL_WIDTH,
            cellHeight: CELL_HEIGHT
        });

        // NESW convention.
        // 1111 = +, 0000 = space
        // 1 = we have a connection in that direction
        // 0 = we don't
        // X = we haven't decided yet
        this.canvasView.drawCell = function(ctx, value, playfieldX, playfieldY,
                                            canvasX, canvasY, cellWidth, cellHeight) {
            var cx; var cy; var q1; var q2;
            var drawArc = false;

            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();
            }
        };

        this.animation = (new yoob.Animation()).init({'object': this});
        this.animation.start();
    };

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

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

        var north = pf.get(x, y - 1) || 'XXXX';
        var east = pf.get(x + 1, y) || 'XXXX';
        var south = pf.get(x, y + 1) || 'XXXX';
        var west = pf.get(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.put(x, y, pick);

        return true;
    };

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

    this.draw = function() {
        this.canvasView.draw();
    };
}