|
|
|
@ -13,14 +13,14 @@ Board.prototype.drawRobots = function(robots) { |
|
|
|
|
this.robots = {}; |
|
|
|
|
|
|
|
|
|
robots.forEach(({ color, i, j }) => { |
|
|
|
|
this.robots[`${i}-${j}`] = true; |
|
|
|
|
|
|
|
|
|
const { x, y } = this.squares.ijToXy({ i, j }); |
|
|
|
|
const s = this.squares.sideLength; |
|
|
|
|
const id = color.replace('#', '').toUpperCase(); |
|
|
|
|
const ij = `${i}-${j}`; |
|
|
|
|
this.robots[ij] = id; |
|
|
|
|
|
|
|
|
|
// Get robot from ij: document.querySelector('[data-robot=i-j]')
|
|
|
|
|
const robot = document.createElement('div'); |
|
|
|
|
robot.id = `robot-${id}`; |
|
|
|
|
robot.className = 'content-robot'; |
|
|
|
|
robot.style.background = `radial-gradient(circle at ${s/3}px ${s/3}px, ${color} 10%, #000)`; |
|
|
|
|
robot.style.borderRadius = (s / 2) + 'px'; |
|
|
|
@ -28,87 +28,64 @@ Board.prototype.drawRobots = function(robots) { |
|
|
|
|
robot.style.width = s + 'px'; |
|
|
|
|
robot.style.left = x + 'px'; |
|
|
|
|
robot.style.top = y + 'px'; |
|
|
|
|
robot.id = id; |
|
|
|
|
robot.dataset.robot = `${i}-${j}`; |
|
|
|
|
|
|
|
|
|
const shadow = document.createElement('div'); |
|
|
|
|
shadow.className = 'content-shadow'; |
|
|
|
|
shadow.style.background = `radial-gradient(circle at ${s/3}px ${s/3}px, ${color} 10%, #000)`; |
|
|
|
|
shadow.style.borderRadius = (s / 2) + 'px'; |
|
|
|
|
shadow.style.height = s + 'px'; |
|
|
|
|
shadow.style.width = s + 'px'; |
|
|
|
|
shadow.style.left = x + 'px'; |
|
|
|
|
shadow.style.top = y + 'px'; |
|
|
|
|
shadow.id = `shadow-${id}`; |
|
|
|
|
shadow.dataset.parentRobot = id; |
|
|
|
|
shadow.dataset.currentIJ = `${i}-${j}`; |
|
|
|
|
|
|
|
|
|
const up = document.createElement('div'); |
|
|
|
|
up.className = 'content-arrow'; |
|
|
|
|
up.innerHTML = "▲" |
|
|
|
|
up.style.left = x + 'px'; |
|
|
|
|
up.style.top = (y - s) + 'px'; |
|
|
|
|
up.style.lineHeight = s + 'px'; |
|
|
|
|
up.style.height = s + 'px'; |
|
|
|
|
up.style.width = s + 'px'; |
|
|
|
|
up.dataset.i = i; |
|
|
|
|
up.dataset.j = j; |
|
|
|
|
up.dataset.direction = 'up'; |
|
|
|
|
up.dataset.parentRobot = id; |
|
|
|
|
up.addEventListener('click', this.moveRobot.bind(this)); |
|
|
|
|
|
|
|
|
|
const down = document.createElement('div'); |
|
|
|
|
down.className = 'content-arrow'; |
|
|
|
|
down.innerHTML = "▼" |
|
|
|
|
down.style.left = x + 'px'; |
|
|
|
|
down.style.top = (y + s) + 'px'; |
|
|
|
|
down.style.lineHeight = s + 'px'; |
|
|
|
|
down.style.height = s + 'px'; |
|
|
|
|
down.style.width = s + 'px'; |
|
|
|
|
down.dataset.i = i; |
|
|
|
|
down.dataset.j = j; |
|
|
|
|
down.dataset.direction = 'down'; |
|
|
|
|
down.dataset.parentRobot = id; |
|
|
|
|
down.addEventListener('click', this.moveRobot.bind(this)); |
|
|
|
|
|
|
|
|
|
const left = document.createElement('div'); |
|
|
|
|
left.className = 'content-arrow'; |
|
|
|
|
left.innerHTML = "◀" |
|
|
|
|
left.style.left = (x - s) + 'px'; |
|
|
|
|
left.style.top = y + 'px'; |
|
|
|
|
left.style.lineHeight = s + 'px'; |
|
|
|
|
left.style.height = s + 'px'; |
|
|
|
|
left.style.width = s + 'px'; |
|
|
|
|
left.dataset.i = i; |
|
|
|
|
left.dataset.j = j; |
|
|
|
|
left.dataset.direction = 'left'; |
|
|
|
|
left.dataset.parentRobot = id; |
|
|
|
|
left.addEventListener('click', this.moveRobot.bind(this)); |
|
|
|
|
|
|
|
|
|
const right = document.createElement('div'); |
|
|
|
|
right.className = 'content-arrow'; |
|
|
|
|
right.innerHTML = "▶" |
|
|
|
|
right.style.left = (x + s) + 'px'; |
|
|
|
|
right.style.top = y + 'px'; |
|
|
|
|
right.style.lineHeight = s + 'px'; |
|
|
|
|
right.style.height = s + 'px'; |
|
|
|
|
right.style.width = s + 'px'; |
|
|
|
|
right.dataset.i = i; |
|
|
|
|
right.dataset.j = j; |
|
|
|
|
right.dataset.direction = 'right'; |
|
|
|
|
right.dataset.parentRobot = id; |
|
|
|
|
right.addEventListener('click', this.moveRobot.bind(this)); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// this.parent.appendChild(robot);
|
|
|
|
|
this.parent.appendChild(shadow); |
|
|
|
|
this.parent.appendChild(up); |
|
|
|
|
this.parent.appendChild(down); |
|
|
|
|
this.parent.appendChild(left); |
|
|
|
|
this.parent.appendChild(right); |
|
|
|
|
|
|
|
|
|
// shadow.addEventListener('mousedown', this.onRobotDragStart.bind(this));
|
|
|
|
|
robot.dataset.i = i; |
|
|
|
|
robot.dataset.j = j; |
|
|
|
|
|
|
|
|
|
// Get robot from ij: document.querySelector('[data-robot=i-j]')
|
|
|
|
|
// robot.dataset.robot = ij;
|
|
|
|
|
|
|
|
|
|
const arrows = document.createElement('div'); |
|
|
|
|
arrows.className = 'content-arrows'; |
|
|
|
|
arrows.id = `arrows-${id}`; |
|
|
|
|
arrows.style.position = 'absolute'; |
|
|
|
|
arrows.style.left = (x - s) + 'px'; |
|
|
|
|
arrows.style.top = (y - s) + 'px'; |
|
|
|
|
|
|
|
|
|
const up = this.drawArrow({ |
|
|
|
|
direction: 'up', label: '▲', i, j, left: s, top: 0, parentId: id |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
const down = this.drawArrow({ |
|
|
|
|
direction: 'down', label: '▼', i, j, left: s, top: (2 * s), parentId: id |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
const left = this.drawArrow({ |
|
|
|
|
direction: 'left', label: '◀', i, j, left: 0, top: s, parentId: id |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
const right = this.drawArrow({ |
|
|
|
|
direction: 'right', label: '▶', i, j, left: (2 * s), top: s, parentId: id |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
arrows.appendChild(up); |
|
|
|
|
arrows.appendChild(down); |
|
|
|
|
arrows.appendChild(left); |
|
|
|
|
arrows.appendChild(right); |
|
|
|
|
|
|
|
|
|
this.parent.appendChild(robot); |
|
|
|
|
this.parent.appendChild(arrows); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
this.updateArrowVisibilities(); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
Board.prototype.drawArrow = function({ direction, label, i, j, left, top, parentId }) { |
|
|
|
|
const s = this.squares.sideLength; |
|
|
|
|
|
|
|
|
|
const arrow = document.createElement('div'); |
|
|
|
|
arrow.className = 'content-arrow'; |
|
|
|
|
arrow.innerHTML = label; |
|
|
|
|
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.dataset.direction = direction; |
|
|
|
|
arrow.dataset.parent = parentId; |
|
|
|
|
|
|
|
|
|
arrow.addEventListener('click', this.onArrowClick.bind(this)); |
|
|
|
|
|
|
|
|
|
return arrow; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
Board.prototype.drawSquares = function() { |
|
|
|
@ -163,21 +140,71 @@ Board.prototype.drawWalls = function(edges) { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
this.parent.appendChild(wall) |
|
|
|
|
}) |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
this.updateArrowVisibilities(); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
Board.prototype.moveRobot = function(evt) { |
|
|
|
|
const i = evt.currentTarget.dataset.i * 1; |
|
|
|
|
const j = evt.currentTarget.dataset.j * 1; |
|
|
|
|
Board.prototype.moveRobot = function({ id, i, j }) { |
|
|
|
|
const robot = document.getElementById(`robot-${id}`); |
|
|
|
|
const arrows = document.getElementById(`arrows-${id}`); |
|
|
|
|
|
|
|
|
|
const { x, y } = this.squares.ijToXy({ i, j }); |
|
|
|
|
const s = this.squares.sideLength; |
|
|
|
|
|
|
|
|
|
robot.style.left = x + 'px'; |
|
|
|
|
robot.style.top = y + 'px'; |
|
|
|
|
robot.dataset.i = i; |
|
|
|
|
robot.dataset.j = j; |
|
|
|
|
|
|
|
|
|
this.robots[`${i}-${j}`] = id; |
|
|
|
|
|
|
|
|
|
arrows.style.left = (x - s) + 'px'; |
|
|
|
|
arrows.style.top = (y - s) + 'px'; |
|
|
|
|
|
|
|
|
|
this.updateArrowVisibilities(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Board.prototype.updateArrowVisibilities = function() { |
|
|
|
|
const keys = Object.keys(this.robots); |
|
|
|
|
|
|
|
|
|
keys.forEach(key => { |
|
|
|
|
const id = this.robots[key]; |
|
|
|
|
const i = key.split('-')[0] * 1; |
|
|
|
|
const j = key.split('-')[1] * 1; |
|
|
|
|
|
|
|
|
|
const arrows = document.getElementById(`arrows-${id}`); |
|
|
|
|
|
|
|
|
|
const ijR = `${i + 1}-${j}`;
|
|
|
|
|
const ijL = `${i - 1}-${j}`;
|
|
|
|
|
const ijU = `${i}-${j - 1}`;
|
|
|
|
|
const ijD = `${i}-${j + 1}`;
|
|
|
|
|
|
|
|
|
|
const edgeR = `${i + 1}-${j}-${i + 1}-${j + 1}`; |
|
|
|
|
const edgeL = `${i}-${j}-${i}-${j + 1}`; |
|
|
|
|
const edgeU = `${i}-${j}-${i + 1}-${j}`; |
|
|
|
|
const edgeD = `${i}-${j + 1}-${i + 1}-${j + 1}`; |
|
|
|
|
|
|
|
|
|
arrows.querySelector("[data-direction='right']").style.display = (this.robots[ijR] || this.walls[edgeR] || i === (this.squares.perSide - 1)) ? 'none' : 'block'; |
|
|
|
|
arrows.querySelector("[data-direction='left']").style.display = (this.robots[ijL] || this.walls[edgeL] || i === 0) ? 'none' : 'block'; |
|
|
|
|
arrows.querySelector("[data-direction='up']").style.display = (this.robots[ijU] || this.walls[edgeU] || j === 0) ? 'none' : 'block'; |
|
|
|
|
arrows.querySelector("[data-direction='down']").style.display = (this.robots[ijD] || this.walls[edgeD] || j === (this.squares.perSide - 1)) ? 'none' : 'block'; |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Board.prototype.onArrowClick = function(evt) { |
|
|
|
|
const direction = evt.currentTarget.dataset.direction; |
|
|
|
|
const id = evt.currentTarget.dataset.parentRobot; |
|
|
|
|
const id = evt.currentTarget.dataset.parent; |
|
|
|
|
|
|
|
|
|
const robot = document.getElementById(`robot-${id}`); |
|
|
|
|
const i = robot.dataset.i * 1; |
|
|
|
|
const j = robot.dataset.j * 1; |
|
|
|
|
|
|
|
|
|
delete this.robots[`${i}-${j}`]; |
|
|
|
|
|
|
|
|
|
const { i: i2, j: j2 } = this.findNextObstacle({ direction, i, j }); |
|
|
|
|
|
|
|
|
|
const {x, y} = this.squares.ijToXy({ i: i2, j: j2 }); |
|
|
|
|
const robot = document.getElementById(`shadow-${id}`); |
|
|
|
|
robot.style.left = x + 'px' |
|
|
|
|
robot.style.top = y + 'px' |
|
|
|
|
this.moveRobot({ id, i: i2, j: j2 }) |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
Board.prototype.findNextObstacle = function({ direction, i, j }) { |
|
|
|
@ -185,9 +212,9 @@ Board.prototype.findNextObstacle = function({ direction, i, j }) { |
|
|
|
|
case 'right': |
|
|
|
|
for (let ii = i + 1; ii < this.squares.perSide; ii++) { |
|
|
|
|
const edge = `${ii + 1}-${j}-${ii + 1}-${j + 1}`; |
|
|
|
|
const ij = `${ii}-${j}`; |
|
|
|
|
const ij = `${ii + 1}-${j}`; |
|
|
|
|
|
|
|
|
|
if (this.robots[ij] || this.walls[edge]) { |
|
|
|
|
if (this.robots[ij] || this.walls[edge] || ii === (this.squares.perSide - 1)) { |
|
|
|
|
return { i: ii, j }; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -195,9 +222,9 @@ Board.prototype.findNextObstacle = function({ direction, i, j }) { |
|
|
|
|
case 'left': |
|
|
|
|
for (let ii = i - 1; ii >= 0; ii--) { |
|
|
|
|
const edge = `${ii}-${j}-${ii}-${j + 1}`; |
|
|
|
|
const ij = `${ii}-${j}`; |
|
|
|
|
const ij = `${ii - 1}-${j}`; |
|
|
|
|
|
|
|
|
|
if (this.robots[ij] || this.walls[edge]) { |
|
|
|
|
if (this.robots[ij] || this.walls[edge] || ii === 0) { |
|
|
|
|
return { i: ii, j }; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -206,9 +233,9 @@ Board.prototype.findNextObstacle = function({ direction, i, j }) { |
|
|
|
|
case 'up': |
|
|
|
|
for (let jj = j - 1; jj >= 0; jj--) { |
|
|
|
|
const edge = `${i}-${jj}-${i + 1}-${jj}`; |
|
|
|
|
const ij = `${i}-${jj}`; |
|
|
|
|
const ij = `${i}-${jj - 1}`; |
|
|
|
|
|
|
|
|
|
if (this.robots[ij] || this.walls[edge]) { |
|
|
|
|
if (this.robots[ij] || this.walls[edge] || jj === 0) { |
|
|
|
|
return { i, j: jj }; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -217,9 +244,9 @@ Board.prototype.findNextObstacle = function({ direction, i, j }) { |
|
|
|
|
case 'down': |
|
|
|
|
for (let jj = j + 1; jj < this.squares.perSide; jj++) { |
|
|
|
|
const edge = `${i}-${jj + 1}-${i + 1}-${jj + 1}`; |
|
|
|
|
const ij = `${i}-${jj}`; |
|
|
|
|
const ij = `${i}-${jj + 1}`; |
|
|
|
|
|
|
|
|
|
if (this.robots[ij] || this.walls[edge]) { |
|
|
|
|
if (this.robots[ij] || this.walls[edge] || jj === (this.squares.perSide - 1)) { |
|
|
|
|
return { i, j: jj }; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -228,112 +255,3 @@ Board.prototype.findNextObstacle = function({ direction, i, j }) { |
|
|
|
|
|
|
|
|
|
throw Error("Could not find next obstacle, no direction found. ", direction, i, j); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// i1 and j1 are the original position.
|
|
|
|
|
// i2 and j2 are the requested position.
|
|
|
|
|
// Check all the edges crossed between the two to find if it's a valid move.
|
|
|
|
|
// Board.prototype.getBlockers = function({ i1, j1, i2, j2 }) {
|
|
|
|
|
// if (i1 !== i2 && j1 !== j2) {
|
|
|
|
|
// return "diagonal move";
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// if (i1 === i2 && j1 == j2) {
|
|
|
|
|
// return;
|
|
|
|
|
// } else if (i1 === i2 && j1 > j2) {
|
|
|
|
|
// // Moving up.
|
|
|
|
|
// for (let j = j2; j < j1; j++) {
|
|
|
|
|
// const edge = `${i1}-${j + 1}-${i1 + 1}-${j + 1}`;
|
|
|
|
|
// const ij = `${i1}-${j}`;
|
|
|
|
|
|
|
|
|
|
// if (this.robots[ij]) {
|
|
|
|
|
// return document.querySelector(`[data-robot='${ij}']`);
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// if (this.walls[edge]) {
|
|
|
|
|
// return document.querySelector(`[data-wall='${edge}']`);
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// } else if (i1 === i2 && j1 < j2) {
|
|
|
|
|
// // Moving down.
|
|
|
|
|
// for (let j = j1; j < j2; j++) {
|
|
|
|
|
// const edge = `${i1}-${j + 1}-${i1 + 1}-${j + 1}`;
|
|
|
|
|
// const ij = `${i1}-${j + 1}`;
|
|
|
|
|
|
|
|
|
|
// if (this.robots[ij]) {
|
|
|
|
|
// return document.querySelector(`[data-robot='${ij}']`);
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// if (this.walls[edge]) {
|
|
|
|
|
// return document.querySelector(`[data-wall='${edge}']`);
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// } else if (j1 === j2 && i1 < i2) {
|
|
|
|
|
// // Moving right.
|
|
|
|
|
// for (let i = i1; i < i2; i++) {
|
|
|
|
|
// const edge = `${i + 1}-${j1}-${i + 1}-${j1 + 1}`;
|
|
|
|
|
// const ij = `${i + 1}-${j1}`;
|
|
|
|
|
|
|
|
|
|
// if (this.robots[ij]) {
|
|
|
|
|
// return document.querySelector(`[data-robot='${ij}']`);
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// if (this.walls[edge]) {
|
|
|
|
|
// return document.querySelector(`[data-wall='${edge}']`);
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// } else {
|
|
|
|
|
// // Moving left.
|
|
|
|
|
// for (let i = i2; i < i1; i++) {
|
|
|
|
|
// const edge = `${i + 1}-${j1}-${i + 1}-${j1 + 1}`;
|
|
|
|
|
// const ij = `${i}-${j1}`;
|
|
|
|
|
|
|
|
|
|
// if (this.robots[ij]) {
|
|
|
|
|
// return document.querySelector(`[data-robot='${ij}']`);
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// if (this.walls[edge]) {
|
|
|
|
|
// return document.querySelector(`[data-wall='${edge}']`);
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// };
|
|
|
|
|
|
|
|
|
|
// Board.prototype.onRobotDragStart = function(evt) {
|
|
|
|
|
// evt.stopPropagation();
|
|
|
|
|
// evt.preventDefault();
|
|
|
|
|
|
|
|
|
|
// this.listeners.onRobotDragStop = this.onRobotDragStop.bind(this);
|
|
|
|
|
// this.listeners.onRobotDrag = this.onRobotDrag.bind(this, evt.currentTarget);
|
|
|
|
|
|
|
|
|
|
// document.body.addEventListener('mouseup', this.listeners.onRobotDragStop);
|
|
|
|
|
// document.body.addEventListener('mousemove', this.listeners.onRobotDrag);
|
|
|
|
|
|
|
|
|
|
// const { x, y } = this.squares.ijToXy(this.squares.xyToIj(evt));
|
|
|
|
|
|
|
|
|
|
// evt.currentTarget.style.left = x + 'px';
|
|
|
|
|
// evt.currentTarget.style.top = y + 'px';
|
|
|
|
|
// };
|
|
|
|
|
|
|
|
|
|
// Board.prototype.onRobotDrag = function(dragTarget, evt) {
|
|
|
|
|
// const [ i1, j1 ] = dragTarget.dataset.currentIJ.split('-').map(v => v * 1);
|
|
|
|
|
// // cost { i: i1, j: j1 } = this.squares.xyToIj({ x: evt.x - evt.movementX, y: evt.y - evt.movementY });
|
|
|
|
|
// const { i: i2, j: j2 } = this.squares.xyToIj({ x: evt.x, y: evt.y });
|
|
|
|
|
|
|
|
|
|
// const blockage = this.getBlockers({ i1, j1, i2, j2 });
|
|
|
|
|
|
|
|
|
|
// if (blockage) {
|
|
|
|
|
// // console.log(blockage)
|
|
|
|
|
// return;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// const { x, y } = this.squares.ijToXy({ i: i2, j: j2 });
|
|
|
|
|
|
|
|
|
|
// dragTarget.style.left = x + 'px';
|
|
|
|
|
// dragTarget.style.top = y + 'px';
|
|
|
|
|
// };
|
|
|
|
|
|
|
|
|
|
// Board.prototype.onRobotDragStop = function(_) {
|
|
|
|
|
// document.body.removeEventListener('mouseup', this.listeners.onRobotDragStop);
|
|
|
|
|
// document.body.removeEventListener('mousemove', this.listeners.onRobotDrag);
|
|
|
|
|
// };
|