Pi with Matchsticks

by alancnet

HTML

<div ng-app ng-controller="Matchsticks as ctrl">
    <a href="" ng-hide="showSettings" ng-click="showSettings=true">Show Settings</a>
    <a href="" ng-show="showSettings" ng-click="showSettings=false">Hide Settings</a>
    <table>
        <tr>
            <th>Presets</th>
            <td>
                <button ng-click="
                    ctrl.find = 'π';
                ">Find π</button> 
                <button ng-click="
                    ctrl.find = 'τ';
                ">Find τ</button>&nbsp;&nbsp;
                <button ng-click="
                    ctrl.loops = 200;
                    ctrl.rate = 500;
                ">Slow</button> 
                <button ng-click="
                    ctrl.loops = 100000;
                    ctrl.rate = 1;
                ">Rapid</button>&nbsp;&nbsp;
                <button ng-click="
                    ctrl.matchstickLength = 10;
                    ctrl.fieldSize = 16;
                ">Small</button>
                <button ng-click="
                    ctrl.matchstickLength = 20;
                    ctrl.fieldSize = 12;
                ">Medium</button>
                <button ng-click="
                    ctrl.matchstickLength = 80;
                    ctrl.fieldSize = 4;
                ">Large</button>
            </td>
        </tr>
        <tr ng-show="showSettings">
            <th>Visual Style</th>
            <td>
                <select ng-model="ctrl.visualStyle">
                    <option value="accumulate">Accumulate</option>
                    <option value="fade">Fade out</option>
                    <option value="clear">Clear every frame</option>
                </select>
            </td>
        </tr>
        <tr ng-show="showSettings">
            <th>Find</th>
            <td>
                <select ng-model="ctrl.find">
                    <option value="π">π pi (3.14)</option>
                    <option value="τ">τ tau (6.28)</option>
                </select>
           ...

CSS

canvas {
    border: solid 1px black;
}
a, th {
    font-family: sans-serif;
    text-align: left;
    font-size: 10pt;
}

JavaScript

function Matchsticks($scope) {
    var ctrl = {
        find: 'π',
        matchstickLength: 20,
        matchstickCount: 20,
        fieldSize: 12, // In matchstick lengths
        loops: 200,
        rate: 500,
        visualStyle: 'fade' // accumulate, clear, fade
    }
    
    $scope.$watch(function() {
        run(
            +ctrl.matchstickLength,
            +ctrl.matchstickCount,
            +ctrl.fieldSize,
            +ctrl.loops,
            +ctrl.rate,
            ctrl.find,
            ctrl.visualStyle
        );
    });
    
    return ctrl;
}
function run(matchstickLength, matchstickCount, fieldSize, loops, rate, find, visualStyle) {
    var canvas = run.canvas || (run.canvas = document.getElementById("canvas"));
    var ctx = run.ctx || (run.ctx = canvas.getContext("2d"));
    ctx.restore();
    if (visualStyle == 'accumulate') ctx.globalCompositeOperation = "lighten";
    else {
        console.log('findme')
        ctx.globalCompositeOperation = "source-over";
    }
    var totalCount = 0;
    var totalCrossed = 0;
    
    // Convert field size to pixels
    fieldSize *= matchstickLength;
    
    ctx.save();
    ctx.saved = true;
    
    // Clear
    ctx.clearRect(0,0,canvas.width,canvas.height);
    
    // Adjust for field
    ctx.translate((canvas.width - fieldSize)/2, (canvas.height - fieldSize)/2);
    var lines;
    
    function drawField() {
        // Fade out background
        if (visualStyle != 'accumulate') {
            if (visualStyle == 'fade') ctx.fillStyle = "rgba(255,255,255,.05)";
            else if (visualStyle == 'clear') ctx.fillStyle = "rgba(255,255,255,1)";
            ctx.fillRect(-canvas.width, -canvas.height, canvas.width * 4, canvas.height * 4);
        }
        
        // Draw field
        ctx.strokeRect(0,0,fieldSize,fieldSize);
        
        // Determine lines, Draw lines
        ctx.strokeStyle = "green";
        var columnWidth = matchstickLength;
        // Pi or Tau?
        if (find == 'π')...