chasers torroidal

by John Doe

HTML

<script src="https://d3js.org/d3.v4.min.js"></script>
<svg id="field"></svg> <br/>
<button id="init">Init</button>
<button id="start">Start</button>
<button id="step">Step</button>
<button id="stop">Stop</button>

<br/>

<div id="configuration">
  Field width: <input id="fieldWidth" type="number" step="1" value="400"/> |
  Field height: <input id="fieldHeight" type="number" step="1" value="300"/> |
  Field margin: <input id="fieldMargin" type="number" step="1" value="20"/> <br/>
  Fleers: <input id="fleers" type="number" step="1" value="400"/> |
  Chasers: <input id="chasers" type="number" step="1" value="20"/> <br/>
  Player radius: <input id="playerRadius" type="number" step="1" value="3"/> <br/>
  Fleer speed: <input id="fleerSpeed" type="number" step="0.01" value="1"/> |
  Chaser speed: <input id="chaserSpeed" type="number" step="0.01" value="1.05"/> <br/>
  Delay per frame: <input id="gameFrameDelay" type="number" step="1" value="10"/>
</div>

<p>
  Note: fleer speed is a multiple of player radius and chaser speed is a multiple of fleer speed.
</p>

<hr/>
<p>Consolelog: <button id="clear">Clear</button></p>
<p id="consolelog" style="border: 1px solid gray"></p>

CSS

#configuration input {
  width: 4em;
}

JavaScript

"use strict";

/* Summary of rules:
*   - Players are either 1) chasing, 2) fleeing, or 3) frozen
*   - Any non-chaser player that a chaser touches is frozen
*   - Non-frozen players can touch frozen players to unfreeze them
*   - Players cannot leave the playing area
*/

var fleers = 800;
var chasers = 20;
var fleerSpeed = 1;
var chaserSpeed = 1.05;

var playerRadius = 5;
var players = [];

var fieldWidth = 400;
var fieldHeight = 300;
var fieldMargin = 20;

var gameTimer;
var gameFrameDelay = 10; // millisecs per frame

var field = d3.select('#field');
field.append('rect')
    .attr('fill', 'white')
    .attr('stroke', 'black')
    .attr('stroke-width', '2px');

function log(output) {
	var outbox = d3.select("#consolelog");
  outbox.html(outbox.html() + "&gt; " + output + "<br/>");
}
function prelog(output) {
	var outbox = d3.select("#consolelog");
  outbox.html("$$ " + output + "<br/>" + outbox.html());
}
// log("Hello world!");
// log("Logger test.");

function init() {
  clear();
	players = [];
  d3.selectAll('.player').remove();
  
  d3.selectAll('#configuration input').each(function(d, i) {
  	var elem = d3.select(this);
    var name = elem.attr('id');
    var value = parseFloat(elem.property('value'));
    log(name + ": " + value);
    eval(name + "=" + value);
  });
  log("playerRadius: " + playerRadius);
  
  field.attr('width', fieldWidth).attr('height', fieldHeight);
  field.select('rect')
    .attr('width', fieldWidth)
    .attr('height', fieldHeight);
  
  actors['fleer']['speed'] = playerRadius * fleerSpeed;
  actors['chaser']['speed'] = actors['fleer']['speed'] * chaserSpeed;
  
  for(var i = 0; i < fleers; i++) {
  	players.push(newPlayer('fleer'));
  }
  for(var i = 0; i < chasers; i++) {
  	players.push(newPlayer('chaser'));
  }   
  
  draw();
  draw(); // for whatever reason, one draw isn't enough
}

function start() {
	if(!gameTimer) {
  	gameTimer = setInterval(step, gameFrameDelay);
  }
}

function stop() {
	if(gameTimer)...