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 = `radial-gradient(circle at ${s/3}px ${s/3}px, ${color} 10%, #000)`; 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 = `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)); }); }; 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) }) }; Board.prototype.moveRobot = function(evt) { const i = evt.currentTarget.dataset.i * 1; const j = evt.currentTarget.dataset.j * 1; const direction = evt.currentTarget.dataset.direction; const id = evt.currentTarget.dataset.parentRobot; 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' }; Board.prototype.findNextObstacle = function({ direction, i, j }) { switch (direction) { 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}`; if (this.robots[ij] || this.walls[edge]) { return { i: ii, j }; } } break; case 'left': for (let ii = i - 1; ii >= 0; ii--) { const edge = `${ii}-${j}-${ii}-${j + 1}`; const ij = `${ii}-${j}`; if (this.robots[ij] || this.walls[edge]) { return { i: ii, j }; } } break; case 'up': for (let jj = j - 1; jj >= 0; jj--) { const edge = `${i}-${jj}-${i + 1}-${jj}`; const ij = `${i}-${jj}`; if (this.robots[ij] || this.walls[edge]) { return { i, j: jj }; } } break; 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}`; if (this.robots[ij] || this.walls[edge]) { return { i, j: jj }; } } break; } 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); // };