maze.js

22/2 2012
gjort ☯︎ js slump

Maze.js draws a maze to a canvas. It works like this, and looks like this:

//
// © 2012 lhli.net.
// Licence: http://creativecommons.org/licenses/by-sa/3.0/
//
/* example:
var maze = new Maze(
    document.getElementById("mazeCanvas").getContext("2d"),
    100,
    100,
    '#000',
    true,
    true); */


function Maze(canvasContext, width, height, color, fullWindow, drawRandomly) {
   
    var _c = canvasContext;
    var _width = width || 10;
    var _height = height || 10;
    var _drawRandomly = drawRandomly || true;
    var _color = color || 'rgba(0, 0, 0, 1)';
   
    var _pixelWidth = 5;
    var _lineWidth = 2;
   
    var _thisPixel = null;
    var _prevPixel = new Pixel(0,0,-1);
   
    var _chunkSize = 10;
    var _tick = 0;
   
    if (fullWindow) {
        _c.canvas.width  = window.innerWidth;
        _c.canvas.height = window.innerHeight;
        _width = Math.floor(window.innerWidth/_pixelWidth);
        _height = Math.floor(window.innerHeight/_pixelWidth);
    } else {
        _c.canvas.width  = _width*_pixelWidth;
        _c.canvas.height = _height*_pixelWidth;
    }
   
    var _matrix = (function () {
        var m = [];
        for (var x=0; x < _width; x++) {
            m.push([]);
            for (var y=0; y < _height; y++) {
                m[x].push(new Pixel(x,y,0));
            };
        };     
        return m;
    })();
   
    var _whitePixels = (function () {
        var w = [];
        for (var x=0; x < _width; x++) {
            for (var y=0; y < _height; y++) {
                w.push(new Pixel(x,y,0));
            };
        };
        return w;
    })();

    _c.fillStyle = _color;
    _c.strokeStyle = _color;
    _c.lineWidth = _lineWidth;
    _c.lineJoin = _c.lineCap = 'round';
   
    render();
    function render() {
        if (_thisPixel === null) {
            _thisPixel = getWhitePixel();
            if (_thisPixel === null) return;
        };     
       
        _thisPixel.state = getState(_thisPixel);
       
        renderPixel(_thisPixel, _prevPixel);
        setAsBlackPixel(_thisPixel);
               
        _prevPixel = _thisPixel;
        _thisPixel = setNextPixel(_thisPixel);
               
        if (_tick<_chunkSize) {
            _tick++;
            render();
        } else {
            _tick = 0;
            setTimeout(function() { render(); }, 1);
        }
    }
   
    function getState(p) {
        var states = [1,2,3,4];
        while (true) {
            if (states.length > 0) {
                var state = states[Math.floor(Math.random()*states.length)];
                states.splice(states.indexOf(state),1);
            } else { return -1; }
            try {
                switch (state){
                    // u,r,d,l
                    case 1: if (_matrix[p.x][p.y-1].state === 0) return state;
                    break;
                    case 2: if (_matrix[p.x+1][p.y].state === 0) return state;
                    break;
                    case 3: if (_matrix[p.x][p.y+1].state === 0) return state;
                    break;
                    case 4: if (_matrix[p.x-1][p.y].state === 0) return state;
                    break;
                }
            } catch (e) {}
        }
    }
   
    function setNextPixel(p) {
        switch (p.state){
            // u,r,d,l
            case 1: return _matrix[p.x][p.y-1];
            case 2: return _matrix[p.x+1][p.y];
            case 3: return _matrix[p.x][p.y+1];
            case 4: return _matrix[p.x-1][p.y];
            default: return null;
        }
    }
   
    function renderPixel(p, pp) {
        var x = p.x*_pixelWidth, y = p.y*_pixelWidth;
        //_c.fillRect(x,y,_pixelWidth,_pixelWidth)
        _c.beginPath();
        switch (pp.state){
            // u,r,d,l
            case 1: _c.moveTo(x+_pixelWidth/2, y+_pixelWidth);
            break;
            case 2: _c.moveTo(x, y+_pixelWidth/2);
            break;
            case 3: _c.moveTo(x+_pixelWidth/2, y);
            break;
            case 4: _c.moveTo(x+_pixelWidth, y+_pixelWidth/2);
            break;
            default: _c.moveTo(x+_pixelWidth/2, y+_pixelWidth/2);
            break;
        }
        _c.lineTo(x+_pixelWidth/2, y+_pixelWidth/2);
        switch (p.state){
            case 1: _c.lineTo(x+_pixelWidth/2, y);
            break;
            case 2: _c.lineTo(x+_pixelWidth, y+_pixelWidth/2);
            break;
            case 3: _c.lineTo(x+_pixelWidth/2, y+_pixelWidth);
            break;
            case 4: _c.lineTo(x, y+_pixelWidth/2);
            break;
            default: _c.lineTo(x+_pixelWidth/2, y+_pixelWidth/2+.5);
            break;
        }
        _c.stroke();
    }
   
    function getWhitePixel() {
        if (!_drawRandomly) {
            for (var y=0; y < _height; y++) {
                for (var x=0; x < _width; x++) {
                    if (_matrix[x][y].state == 0) return _matrix[x][y];
                };
            };
        } else {
            if (_whitePixels.length > 0) {
                var p = _whitePixels[Math.floor(Math.random()*_whitePixels.length)];
                return _matrix[p.x][p.y]
            };
        }
        return null;
    }
   
    function setAsBlackPixel(p) {
        for (var i=0, l=_whitePixels.length; i < l; i++) {             
            if (_whitePixels[i].x == p.x && _whitePixels[i].y == p.y ) {
                _whitePixels.splice(i, 1);             
                break;
            }
        };     
    }
   
    function Pixel(x, y, state) {
        this.x = x;
        this.y = y;
        this.state = state;
    }
}