JSFiddle - React, Tailwind, and code Playground
HTML
<h2>Click a cell to distribute players</h2>
<table id="heat">
</table>
CSS
body {
font-family: sans-serif;
}
h2 {
margin: 1ex 0;
}
td {
border: 1px solid #0af;
padding: 0.5ex;
font-family: monospace;
font-size: 10px;
max-width: 4em;
height: 4em;
overflow: hidden;
text-overflow: ellipsis;
}
td.target {
border-color: #f80;
}
td.player {
border-color: black;
}
td.player::after {
font-family: sans-serif;
content: "player here";
position: absolute;
color: white;
background-color: rgba(0, 0, 0, 0.5);
font-weight: bold;
padding: 2px;
}
JavaScript
var numPlayers = 5;
var numTargets = numPlayers;
var gridSize = numPlayers * 4;
var minDistance = 4;
var targetPositions = [];
for (var i = 0; i < numTargets; i++) {
// TODO: Make sure targets don't get too close
targetPositions[i] = randomPos();
}
var heatMap = [];
for (var i = 0; i < gridSize; i++) {
heatMap[i] = [];
for (var j = 0; j < gridSize; j++) {
heatMap[i][j] = heat(i, j);
}
}
printHeat();
function heat(x, y) {
var result = 0;
for (var i in targetPositions) {
var pos = targetPositions[i];
result += 1 / distance(x - pos.x, y - pos.y); // XXX: What about zero division?
}
return result;
}
function distance(l1, l2) {
// manhattan distance
return Math.abs(l1) + Math.abs(l2);
}
function randomPos() {
return {
x: random(gridSize),
y: random(gridSize),
toString: function() {
return this.x + '/' + this.y
}
};
function random(max) {
return Math.floor(Math.random() * max);
}
}
function printHeat() {
for (var i = 0; i < gridSize; i++) {
var tr = $('<tr>');
$('#heat').append(tr);
for (var j = 0; j < gridSize; j++) {
var heatVal = heatMap[i][j];
var td = $('<td> ' + heatVal + ' </td>');
if (heatVal > numTargets) // hack
td.addClass('target');
td.attr('data-x', i).attr('data-y', j);
td.css('background-color', 'rgb(' + Math.floor(heatVal * 255) + ',160,80)');
tr.append(td);
}
}
}
var cellsSorted = $('td').sort(function(a, b) {
return numOfCell(a) > numOfCell(b);
}).toArray();
$('td').click(function() {
$('.player').removeClass('player');
var index = cellsSorted.indexOf(this);
// TODO: Don't just search downwards, but in both directions with lowest difference
for (var k = 0; k < numPlayers; k++) {
var newIndex = index - k; // XXX Check against outOfBounds
var cell = cellsSorted[newIndex];
if (!validPlayerCell(cell)) {
// skip one
k--;
index--;
continue;
}
...