AngularJS - Forest, a simulated ecosystem

Proposition for a StackExchange - Code Golf challenge (http://codegolf.stackexchange.com/questions/35322/forest-a-simulated-ecosystem)

by Amaury Dalla Monta

HTML

<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.0-beta.17/angular.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.0-beta.17/angular-animate.min.js"></script>
<div ng-app="ForestApp" ng-controller="ForestController">
    <form name="parametersForm" ng-hide="evolutionInProgress" autocomplete="off" novalidate>
        <div class="line">
            <label for="forestSize">Size of the forest:</label>
            <input type="number" ng-model="Parameters.forestSize" id="forestSize" min="5" ng-pattern="/^[0-9]+$/" required />
        </div>
        <div class="line">
            <label for="simulationInterval">Number of milliseconds between each tick</label>
            <input type="number" ng-model="Parameters.simulationInterval" id="simulationInterval" min="10" ng-pattern="/^[0-9]+$/" required />
        </div>
        <div class="line">
            <label for="animationsEnabled">Animations enabled?
                <br /><small>(>= 300 ms between each tick is advisable)</small>

            </label>
            <input type="checkbox" ng-model="Parameters.animationsEnabled" id="animationsEnabled" />
        </div>
        <div class="line">
            <button ng-disabled="parametersForm.$invalid || evolutionInProgress" ng-click="launchEvolution()">Launch the evolution!</button>
        </div>
    </form>
    <div id="forest" ng-style="{width: side = (20*Parameters.forestSize) + 'px', height: side, 'transition-duration': transitionDuration = (Parameters.animationsEnabled ? 0.8*Parameters.simulationInterval : 0) + 'ms', '-webkit-transition-duration': transitionDuration}">
        <div ng-repeat="bear in Forest.bearsList" class="entity entity--bear" ng-style="{left: (20*bear.x) + 'px', top: (20*bear.y) + 'px'}"></div>
        <div ng-repeat="lumberjack in Forest.lumberjacksList" class="entity entity--lumberjack" ng-style="{left: (20*lumberjack.x) + 'px', top: (20*lumberjack.y) + 'px'}"></div>
        <div ng-repeat="tree...

CSS

body {
    padding: 10px;
}
small {
    font-size: smaller;
}
form {
    border-bottom: 1px solid black;
    padding: 5px;
}
.line {
    display: flex;
    justify-content: center;
    margin: 5px;
}
.line * {
    flex: 1;
    max-width: 60%;
}
label, em {
    text-align: right;
    padding-right: 5px;
}
samp {
    position: relative;
    top: 3px;
}
#forest {
    position: relative;
    background-color: beige;
    border: 1px solid maroon;
    border-radius: 10px;
    margin: 10px auto;
    overflow: hidden;
}
.entity {
    width: 20px;
    height: 20px;
    position: absolute;
    transition-duration: inherit;
    -webkit-transition-duration: inherit;
}
.entity.ng-move, .entity.ng-enter, .entity.ng-leave.ng-leave-active {
    opacity: 0;
}
.entity.ng-move.ng-move-active, .entity.ng-enter.ng-enter-active, .entity.ng-leave {
    opacity: 1;
}
.entity--bear, .entity--lumberjack {
    transition-property: left, top, opacity;
    -webkit-transition-property: left, top, opacity;
    z-index: 10;
}
.entity--bear::before, .entity--lumberjack::before {
    content:'';
    display: block;
    width: 50%;
    height: 50%;
    position: relative;
    left: 25%;
    top: 25%;
    border: 1px solid maroon;
}
.entity--bear::before {
    background-color: indianred;
}
.entity--lumberjack::before {
    background-color: khaki;
}
.entity--tree {
    transition-property: background-color, opacity;
    -webkit-transition-property: background-color, opacity;
}
.entity--tree--0 {
    background-color:chartreuse;
}
.entity--tree--1 {
    background-color:forestgreen;
}
.entity--tree--2 {
    background-color:darkolivegreen;
}

JavaScript

/** @link http://stackoverflow.com/questions/2450954/how-to-randomize-shuffle-a-javascript-array */

function shuffle(array) {
    var currentIndex = array.length,
        temporaryValue, randomIndex;

    // While there remain elements to shuffle...
    while (0 !== currentIndex) {

        // Pick a remaining element...
        randomIndex = Math.floor(Math.random() * currentIndex);
        currentIndex -= 1;

        // And swap it with the current element.
        temporaryValue = array[currentIndex];
        array[currentIndex] = array[randomIndex];
        array[randomIndex] = temporaryValue;
    }

    return array;
}

var forestApp = angular.module('ForestApp', ['ngAnimate']);

forestApp.value('Parameters', {
    /** @var int[] Maximal number of moves by species */
    speed: {
        bear: 5,
        lumberjack: 3,
    },

    /** @var int[] Initial percentage of each species in the forest */
    initialPercentage: {
        bear: 2,
        lumberjack: 10,
        tree: 50,
    },

    /** @var int[] Spawing rate, in percentage, of new saplings around an existing tree */
    spawningPercentage: {
        0: 0,
        1: 10,
        2: 20,
    },

    /** @var int[] Age of growth for an existing tree */
    ageOfGrowth: {
        sapling: 12,
        tree: 120,
    },

    /** @var int[] Lumber collected on an existing tree */
    numberOfLumbers: {
        tree: 1,
        elderTree: 2,
    },

    /** @var int Size of each side of the forest */
    forestSize: 20,

    /** @var int Number of milliseconds between each tick (month in the forest) */
    simulationInterval: 50,
});

forestApp.constant('TREE_STAGE', {
    SAPLING: 0,
    TREE: 1,
    ELDER_TREE: 2,
});

forestApp.factory('Tree', ['Forest', 'Parameters', 'TREE_STAGE', function (Forest, Parameters, TREE_STAGE) {
    // Classes which represents a tree
    var Tree = function (stage, x, y) {
        /** @var TREE_STAGE Current stage of the tree */
        this.stage = stage;

        /** @var...