|
|
|
@ -2,17 +2,22 @@ |
|
|
|
|
|
|
|
|
|
const Grid = function() { |
|
|
|
|
this.colors = {}; |
|
|
|
|
this.icons = {}; |
|
|
|
|
this.obstacles = {}; |
|
|
|
|
this.robots = []; |
|
|
|
|
this.shadows = []; |
|
|
|
|
this.walls = []; |
|
|
|
|
this.winstate = {}; |
|
|
|
|
|
|
|
|
|
this.squaresPerSide = 20; |
|
|
|
|
this.squareSideLength = 0; |
|
|
|
|
|
|
|
|
|
document.addEventListener('L-stack', this.msgStack.bind(this)); |
|
|
|
|
document.addEventListener('L-shadows', this.msgShadows.bind(this)); |
|
|
|
|
|
|
|
|
|
document.addEventListener('G-robots', this.msgRobots.bind(this)); |
|
|
|
|
document.addEventListener('G-walls', this.msgWalls.bind(this)); |
|
|
|
|
document.addEventListener('G-winstate', this.msgWinState.bind(this)); |
|
|
|
|
|
|
|
|
|
window.addEventListener('resize', this.debounce(this.onResize.bind(this), 500)); |
|
|
|
|
|
|
|
|
@ -73,27 +78,69 @@ Grid.prototype.drawWalls = function() { |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
Grid.prototype.drawRobots = function() { |
|
|
|
|
const s = this.squareSideLength; |
|
|
|
|
const ids = new Set(); |
|
|
|
|
|
|
|
|
|
this.robots.forEach(({ id, i, j }) => { |
|
|
|
|
const robot = document.getElementById(`robot-${id}`) || this.drawRobot({ id, i, j }); |
|
|
|
|
|
|
|
|
|
robot.style.left = `${i * s}px`; |
|
|
|
|
robot.style.top = `${j * s}px`; |
|
|
|
|
|
|
|
|
|
ids.add(robot.id); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
const grid = document.getElementById('content-grid'); |
|
|
|
|
grid.querySelectorAll('.content-robot').forEach(el => { |
|
|
|
|
if (ids.has(el.id) === false) { |
|
|
|
|
el.parentNode.removeChild(el); |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
Grid.prototype.drawRobot = function({ id, i, j }) { |
|
|
|
|
const grid = document.getElementById('content-grid'); |
|
|
|
|
grid.querySelectorAll('.content-robot').forEach(el => el.parentNode.removeChild(el)); |
|
|
|
|
const color = this.colors[id]; |
|
|
|
|
const s = this.squareSideLength; |
|
|
|
|
|
|
|
|
|
// const robot = document.createElement('div');
|
|
|
|
|
const robot = document.createElement('img'); |
|
|
|
|
robot.src = this.icons[id]; |
|
|
|
|
robot.className = 'content-robot'; |
|
|
|
|
robot.id = `robot-${id}`; |
|
|
|
|
|
|
|
|
|
robot.style.background = color; |
|
|
|
|
|
|
|
|
|
robot.style.height = `${s}px`; |
|
|
|
|
robot.style.width = `${s}px`; |
|
|
|
|
|
|
|
|
|
grid.appendChild(robot); |
|
|
|
|
|
|
|
|
|
return robot; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
Grid.prototype.drawShadows = function() { |
|
|
|
|
const grid = document.getElementById('content-grid'); |
|
|
|
|
grid.querySelectorAll('.content-shadow').forEach(el => el.parentNode.removeChild(el)); |
|
|
|
|
|
|
|
|
|
const s = this.squareSideLength; |
|
|
|
|
|
|
|
|
|
this.robots.forEach(({ id, i, j }) => { |
|
|
|
|
this.shadows.forEach(({ id, i, j }) => { |
|
|
|
|
const color = this.colors[id]; |
|
|
|
|
|
|
|
|
|
const robot = document.createElement('div'); |
|
|
|
|
robot.className = 'content-robot'; |
|
|
|
|
const shadow = document.createElement('img'); |
|
|
|
|
shadow.src = this.icons[id]; |
|
|
|
|
shadow.className = 'content-shadow'; |
|
|
|
|
|
|
|
|
|
robot.style.background = `radial-gradient(circle at ${s/3}px ${s/3}px, ${color} 10%, #000)`; |
|
|
|
|
robot.style.borderRadius = (s / 2) + 'px'; |
|
|
|
|
shadow.style.background = color; |
|
|
|
|
|
|
|
|
|
robot.style.height = s + 'px'; |
|
|
|
|
robot.style.width = s + 'px'; |
|
|
|
|
shadow.style.height = `${s}px`; |
|
|
|
|
shadow.style.width = `${s}px`; |
|
|
|
|
|
|
|
|
|
robot.style.left = `${i * s}px`; |
|
|
|
|
robot.style.top = `${j * s}px`; |
|
|
|
|
shadow.style.left = `${i * s}px`; |
|
|
|
|
shadow.style.top = `${j * s}px`; |
|
|
|
|
|
|
|
|
|
grid.appendChild(robot); |
|
|
|
|
grid.appendChild(shadow); |
|
|
|
|
}); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
@ -138,9 +185,9 @@ Grid.prototype.drawArrow = function({ direction, label, left, top, parentId }) { |
|
|
|
|
|
|
|
|
|
arrow.style.left = left + 'px'; |
|
|
|
|
arrow.style.top = top + 'px'; |
|
|
|
|
arrow.style.lineHeight = s + 'px'; |
|
|
|
|
arrow.style.height = s + 'px'; |
|
|
|
|
arrow.style.width = s + 'px'; |
|
|
|
|
arrow.style.lineHeight = `${s}px`; |
|
|
|
|
arrow.style.height = `${s}px`; |
|
|
|
|
arrow.style.width = `${s}px`; |
|
|
|
|
|
|
|
|
|
arrow.dataset.direction = direction; |
|
|
|
|
arrow.dataset.parent = parentId; |
|
|
|
@ -150,6 +197,38 @@ Grid.prototype.drawArrow = function({ direction, label, left, top, parentId }) { |
|
|
|
|
return arrow; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
Grid.prototype.drawWinState = function() { |
|
|
|
|
if (this.winstate.i === undefined || this.winstate.j === undefined) { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const s = this.squareSideLength; |
|
|
|
|
|
|
|
|
|
const grid = document.getElementById('content-grid'); |
|
|
|
|
grid.querySelectorAll('.content-winstate').forEach(el => el.parentNode.removeChild(el)); |
|
|
|
|
|
|
|
|
|
const star = document.createElementNS("http://www.w3.org/2000/svg", "svg"); |
|
|
|
|
star.setAttribute("viewBox", '0 0 100 100');
|
|
|
|
|
|
|
|
|
|
const path = document.createElementNS("http://www.w3.org/2000/svg", 'path'); |
|
|
|
|
path.setAttribute('d', "M 0,38 L 38,38 L 49,0 L 60,38 L 100,38 L 68,66 L 77,100 L 47,79 L 17,100 L 28,64 Z"); |
|
|
|
|
path.setAttribute('stroke-linecap', 'null'); |
|
|
|
|
path.setAttribute('stroke-linejoin', 'null'); |
|
|
|
|
path.setAttribute('stroke-dasharray', 'null'); |
|
|
|
|
path.setAttribute('stroke-width', '0'); |
|
|
|
|
path.setAttribute('fill', this.colors[this.winstate.id]); |
|
|
|
|
|
|
|
|
|
star.appendChild(path); |
|
|
|
|
star.style.position = 'absolute'; |
|
|
|
|
star.style.zIndex = 100; |
|
|
|
|
star.style.left = '50%' |
|
|
|
|
star.style.top = '50%' |
|
|
|
|
star.style.height = `${s}px`; |
|
|
|
|
star.style.width = `${s}px`; |
|
|
|
|
|
|
|
|
|
grid.appendChild(star); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
//===== Obstacle logic
|
|
|
|
|
// i and j are notations for the grid of squares.
|
|
|
|
|
// x and y are notations for absolute pixels.
|
|
|
|
@ -238,6 +317,15 @@ Grid.prototype.findNextObstacle = function({ direction, i, j }) { |
|
|
|
|
throw Error("Could not find next obstacle, no direction found. ", direction, i, j); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
Grid.prototype.checkWin = function({ id, i, j }) { |
|
|
|
|
if (i !== this.winstate.i || j !== this.winstate.j || id !== this.winstate.id) { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const evtSolve = new Event('L-solve'); |
|
|
|
|
document.dispatchEvent(evtSolve); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
//===== DOM event handlers
|
|
|
|
|
|
|
|
|
|
Grid.prototype.onArrowClick = function(evt) { |
|
|
|
@ -252,6 +340,8 @@ Grid.prototype.onArrowClick = function(evt) { |
|
|
|
|
|
|
|
|
|
const evtMove = new CustomEvent('L-arrow', { detail: { id, i, j } }); |
|
|
|
|
document.dispatchEvent(evtMove); |
|
|
|
|
|
|
|
|
|
this.checkWin({ id, i, j }); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
Grid.prototype.onResize = function() { |
|
|
|
@ -281,6 +371,8 @@ Grid.prototype.onResize = function() { |
|
|
|
|
this.drawWalls(); |
|
|
|
|
this.drawRobots(); |
|
|
|
|
this.drawArrows();
|
|
|
|
|
this.drawShadows(); |
|
|
|
|
this.drawWinState(); |
|
|
|
|
|
|
|
|
|
this.updateArrowVisibilities(); |
|
|
|
|
}; |
|
|
|
@ -296,6 +388,17 @@ Grid.prototype.debounce = function(fn, ms) { |
|
|
|
|
|
|
|
|
|
//===== Message handlers
|
|
|
|
|
|
|
|
|
|
Grid.prototype.msgRobots = function(evt) { |
|
|
|
|
// Do not assign position or redraw here: movements are fully managed using the stack.
|
|
|
|
|
this.colors = {}; |
|
|
|
|
this.icons = {}; |
|
|
|
|
|
|
|
|
|
evt.detail.body.forEach(({ id, color, icon }) => { |
|
|
|
|
this.colors[id] = color; |
|
|
|
|
this.icons[id] = icon; |
|
|
|
|
}, {}); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
Grid.prototype.msgStack = function(evt) { |
|
|
|
|
const latestPositions = evt.detail.reduce((acc, { id, i, j }) => { |
|
|
|
|
acc[id] = { id, i, j }; |
|
|
|
@ -311,6 +414,11 @@ Grid.prototype.msgStack = function(evt) { |
|
|
|
|
this.updateArrowVisibilities(); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
Grid.prototype.msgShadows = function(evt) { |
|
|
|
|
this.shadows = evt.detail; |
|
|
|
|
this.drawShadows(); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
Grid.prototype.msgWalls = function(evt) { |
|
|
|
|
this.walls = evt.detail.body; |
|
|
|
|
|
|
|
|
@ -320,15 +428,11 @@ Grid.prototype.msgWalls = function(evt) { |
|
|
|
|
this.updateArrowVisibilities(); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
Grid.prototype.msgRobots = function(evt) { |
|
|
|
|
// Do not assign position or redraw here: movements are fully managed using the stack.
|
|
|
|
|
this.colors = evt.detail.body.reduce((acc, { color, id }) => { |
|
|
|
|
acc[id] = color; |
|
|
|
|
return acc; |
|
|
|
|
}, {}); |
|
|
|
|
Grid.prototype.msgWinState = function(evt) { |
|
|
|
|
this.winstate = evt.detail.body; |
|
|
|
|
this.drawWinState(); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//============ THE TRASH BIN OF HISTORY
|
|
|
|
|
// Content.prototype.drawRobot = function({ id, i, j }) {
|
|
|
|
|
// const robot = document.getElementById(`robot-${id}`);
|
|
|
|
|