Recipe:
Press q to reveal the field. Press w to hide the field.
Reload to have a new field.
Enjoy :)
xxxxxxxxxx
<meta charset="utf-8">
<style>
body {
max-width: 960px;
margin: 1px;
}
div {
width: 10px;
height: 10px;
margin: 1px 0 0 1px;
float: left;
background: #eee;
display: inline-block;
cursor: pointer;
}
</style>
<body>
<script src="//d3js.org/d3.v4.0.0-alpha.24.min.js"></script>
<script>
var n = 4002;
var bodyWidth = 960;
var width = 10 + 1; // width + margin
var elementPerLines = Math.round(bodyWidth/(10+1));
var numberOfLines = Math.floor(n/elementPerLines)+1;
var whiteblue = d3.interpolateRgb("#eee", "steelblue"),
blueorange = d3.interpolateRgb("steelblue", "orange"),
orangewhite = d3.interpolateRgb("orange", "#eee");
var bombColorScale = d3.scaleCategory10().domain([0, 1, 2, 3, 4]);
var bombsArray = d3.range(n).map(function(i){
return {
bombs: 0,
sensors: 0,
index: i
}
});
placeBombs(500, bombsArray);
var grid = d3.select("body").selectAll("div")
.data(bombsArray, function(d) { return d.index});
var gridUpdate = grid.enter().append("div").merge(grid)
.style('background-color', function(d){
/*if (d.bombs) {
return 'black';
}
if (d.sensors === 0) {
return '#eee';
}
return bombColorScale(d.sensors);*/
})
.on('click', function(d, i, nodes) {
var startingBlockYIndex = Math.floor(i / elementPerLines) * elementPerLines;
var startingBlockXIndex = i % elementPerLines;
crossAnimation(startingBlockXIndex, startingBlockYIndex);
discover(bombsArray, i);
d3.select(this).transition().duration(100).style('background-color',function(d, i){
d.discovered = true;
if (d.bombs) {
return 'black';
}
if (d.sensors === 0) {
return '#EEAAEE';
}
return bombColorScale(d.sensors);
});
});
d3.select("body")
.on("keydown", function() {
console.log(d3.event.keyCode)
if (d3.event.keyCode === 81) {
gridUpdate.style('background-color', function (d) {
d.discovered = true;
if (d.bombs) {
return 'black';
}
if (d.sensors === 0) {
d.discovered = false;
return '#eee';
}
return bombColorScale(d.sensors);
});
} else if (d3.event.keyCode === 87) {
gridUpdate.style('background-color', function (d) {
d.discovered = false;
return '#eee';
});
}
}
);
function checkIfDiscovered(d) {
if (d.discovered) {
if (d.bombs) {
return 'black';
}
if (d.sensors === 0) {
return '#EEAAEE';
}
return bombColorScale(d.sensors);
} else {
return '#eee';
}
}
function crossAnimation(startingBlockXIndex, startingBlockYIndex) {
// Y moves on X
// X moves on Y
// we now we have 89 elements per line
startingBlockYIndex--;
var oppositeYIndex = startingBlockYIndex + elementPerLines-1;
var oppositeXIndex = + (numberOfLines - 2 ) * ( elementPerLines ) + startingBlockXIndex;
var numberOfLinesToGo = (numberOfLines - 2) - Math.floor(startingBlockYIndex / elementPerLines);
var lastLine = (numberOfLines - 2 ) * ( elementPerLines );
var grid = d3.select("body").selectAll("div");
// there must be a better way to do it
grid.filter(function(d, i) { return i > startingBlockYIndex && i <= startingBlockYIndex + startingBlockXIndex; })
.transition()
.delay(function(d, i) { return ( i - startingBlockYIndex) * 10; })
.ease(d3.easeLinear)
.on("start", function repeat() {
d3.active(this)
.styleTween("background-color", function () {
return whiteblue;
}
).transition()
.delay(100)
.style("background-color", checkIfDiscovered
);
}
);
grid.filter(function(d, i) { return i < oppositeYIndex && i > oppositeYIndex - (elementPerLines - startingBlockXIndex - 1); })
.transition()
.delay(function(d, i) { return Math.abs(i - startingBlockYIndex - elementPerLines) * 10; })
.ease(d3.easeLinear)
.on("start", function repeat() {
d3.active(this)
.styleTween("background-color", function () {
return whiteblue;
}
).transition()
.delay(100)
.style("background-color", checkIfDiscovered
);
}
);
var data = {};
for (var i = 0; i <= Math.floor(startingBlockYIndex / elementPerLines); i++) {
data[startingBlockXIndex + elementPerLines * i] = true;
}
var delay = 0;
grid.filter(function(d, i) { return data[i];})
.transition()
.delay(function(d, i) { return (delay++)*10; })
.ease(d3.easeLinear)
.on("start", function repeat() {
d3.active(this)
.styleTween("background-color", function () {
return whiteblue;
}
).transition()
.delay(100)
.style("background-color", checkIfDiscovered
);
}
);
data = {};
for (var i = 0; i <= numberOfLinesToGo; i++) {
data[oppositeXIndex - elementPerLines * i] = true;
}
var delay2 = numberOfLines - numberOfLinesToGo;
// that would be easier if we could reverse the whole stuff
grid.filter(function(d, i) { return data[i];})
.transition()
.delay(function(d, i) { return (delay2--) * 10; })
.ease(d3.easeLinear)
.on("start", function repeat() {
d3.active(this)
.styleTween("background-color", function () {
return whiteblue;
}
).transition()
.delay(100)
.style("background-color", checkIfDiscovered
);
}
);
}
function placeBombs(numberOfBombs, array) {
var n = array.length;
var bombMap = {};
debugger;
for (var i = 0;i < numberOfBombs;i++) {
var bombIndex = Math.round(Math.random() * n);
if (bombMap[bombIndex]) {
i--;
continue;
}
bombMap[bombIndex] = true;
array[bombIndex].bombs = 1;
}
// perform sensorDetection
function cb(_array, _index) {
_array[_index].sensors++;
}
Object.keys(bombMap).forEach(function(bombIndex){
// left
bombIndex = parseInt(bombIndex);
checkEast(array, bombIndex, cb);
checkWest(array, bombIndex, cb);
checkNorthWest(array, bombIndex, cb);
checkNorthEast(array, bombIndex, cb);
checkNorth(array, bombIndex, cb);
checkSouth(array, bombIndex, cb);
checkSouthEast(array, bombIndex, cb);
checkSouthWest(array, bombIndex, cb);
});
}
var discoverCallbackFunction = function(array, index) {
// the stuff is NOT discoverd, so we mark it as discoverd and continue recursion
if (array[index].discovered) { return ;}
var node = gridUpdate.nodes()[index];
d3.select(node).style('background-color', function(d,i) {
if (d.bombs) {
return 'black';
}
if (d.sensors === 0) {
return '#EEAAEE';
}
return bombColorScale(d.sensors);
});
// fire a d3 transition ???????
array[index].discovered = true;
if (array[index].bombs || array[index].sensors) {
return;
}
// continue recursion
discover(array, index);
};
function discover(array, index) {
var bombIndex = index;
var _cb = discoverCallbackFunction;
checkEast(array, bombIndex, _cb, true);
checkWest(array, bombIndex, _cb, true);
checkNorth(array, bombIndex, _cb, true);
checkSouth(array, bombIndex, _cb, true);
//checkNorthWest(array, bombIndex, cb, true);
/*checkNorthEast(array, bombIndex, cb, true);
checkNorth(array, bombIndex, cb, true);
checkSouthEast(array, bombIndex, cb, true);
checkSouthWest(array, bombIndex, cb, true);*/
}
function checkNorth(array, index, callback, shouldCheckIfDiscovered) {
index = index - elementPerLines;
if (index >= 0) {
if (!array[index].bombs){
// si bombe et mode decouverte, on arrete
(!shouldCheckIfDiscovered) && callback(array, index);
(shouldCheckIfDiscovered) && callback(array, index);
}
}
return false;
}
function checkSouth(array, index, callback, shouldCheckIfDiscovered) {
index = index + elementPerLines;
// bottom
if (index < n) {
if (!array[index].bombs) {
(!shouldCheckIfDiscovered) && callback(array, index);
(shouldCheckIfDiscovered ) && callback(array, index);
}
}
return false;
}
function checkWest(array, index, callback, shouldCheckIfDiscovered) {
if (index === 0 || index % (elementPerLines) === 0) {
return false;
}
if (!array[index - 1].bombs){
(!shouldCheckIfDiscovered) && callback(array, index - 1);
(shouldCheckIfDiscovered) && callback(array, index - 1);
}
}
function checkEast(array, index, callback, shouldCheckIfDiscovered) {
if ( (index + 1) % elementPerLines === 0) {
return false;
}
if (!array[index + 1].bombs){
!shouldCheckIfDiscovered && callback(array, index + 1);
(shouldCheckIfDiscovered) && callback(array, index + 1);
}
}
function checkNorthEast(array, index, callback, shouldCheckIfDiscovered) {
if (index - elementPerLines < 0) {
return false;
}
return checkEast(array, index - elementPerLines, callback, shouldCheckIfDiscovered);
}
function checkNorthWest(array, index, callback, shouldCheckIfDiscovered){
if (index - elementPerLines < 0) {
return false;
}
return checkWest(array, index - elementPerLines, callback, shouldCheckIfDiscovered);
}
function checkSouthEast(array, index, callback, shouldCheckIfDiscovered) {
if (index + elementPerLines >= n) {
return false;
}
return checkEast(array, index + elementPerLines, callback, shouldCheckIfDiscovered);
}
function checkSouthWest(array, index, callback, shouldCheckIfDiscovered) {
if (index + elementPerLines >= n) {
return false;
}
return checkWest(array, index + elementPerLines, callback, shouldCheckIfDiscovered);
}
// recursion algorithm for discovery
// check in all direction, stop if discovered, if not discovered continue recursion
</script>
https://d3js.org/d3.v4.0.0-alpha.24.min.js