You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
214 lines
6.6 KiB
214 lines
6.6 KiB
const Board = function({ parent, squares }) {
|
|
this.parent = parent;
|
|
this.squares = squares;
|
|
|
|
this.walls = {};
|
|
this.robots = {};
|
|
this.listeners = {};
|
|
|
|
this.drawSquares();
|
|
};
|
|
|
|
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();
|
|
|
|
// Get robot from ij: document.querySelector('[data-robot=i-j]')
|
|
const robot = document.createElement('div');
|
|
robot.className = 'content-robot';
|
|
robot.style.background = color;
|
|
robot.style.borderRadius = (s / 2) + 'px';
|
|
robot.style.height = s + 'px';
|
|
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 = color;
|
|
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.dataset.parentRobot = id;
|
|
shadow.dataset.currentIJ = `${i}-${j}`;
|
|
|
|
this.parent.appendChild(robot);
|
|
this.parent.appendChild(shadow);
|
|
|
|
shadow.addEventListener('mousedown', this.onRobotDragStart.bind(this));
|
|
});
|
|
};
|
|
|
|
Board.prototype.drawSquares = function() {
|
|
for (let i = 0; i < this.squares.perSide; i++) {
|
|
for (let j = 0; j < this.squares.perSide; j++) {
|
|
// All squares are absolutely positioned relative to the viewport.
|
|
const { x, y } = this.squares.ijToXy({ i, j });
|
|
|
|
const square = document.createElement('div');
|
|
square.className = 'content-square';
|
|
square.style.height = this.squares.sideLength + 'px';
|
|
square.style.width = this.squares.sideLength + 'px';
|
|
square.style.left = x + 'px';
|
|
square.style.top = y + 'px';
|
|
|
|
this.parent.appendChild(square);
|
|
}
|
|
}
|
|
};
|
|
|
|
Board.prototype.drawWalls = function(edges) {
|
|
this.walls = {};
|
|
|
|
edges.forEach(edge => {
|
|
this.walls[edge] = true;
|
|
|
|
const id = `wall-${edge}`;
|
|
|
|
if (document.getElementById(id)) {
|
|
return;
|
|
}
|
|
|
|
const [i1, j1, i2, j2] = edge.split('-');
|
|
|
|
const wall = document.createElement('div');
|
|
wall.id = id;
|
|
wall.title = edge;
|
|
|
|
const { x, y } = this.squares.ijToXy({ i: i1, j: j1 });
|
|
wall.style.left = x + 'px';
|
|
wall.style.top = y + 'px';
|
|
|
|
// Get wall from edge: document.querySelector('[data-wall=i1-j1-i2-j2]')
|
|
wall.dataset.wall = edge;
|
|
|
|
if (i1 === i2) {
|
|
wall.className = 'content-wall-y';
|
|
wall.style.height = this.squares.sideLength + 'px';
|
|
} else {
|
|
wall.className = 'content-wall-x';
|
|
wall.style.width = this.squares.sideLength + 'px';
|
|
}
|
|
|
|
this.parent.appendChild(wall)
|
|
})
|
|
};
|
|
|
|
// 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);
|
|
}; |