Go to page
Part 1 & 2
let [map, ins] = $('*').textContent.trim().split('\n\n');
map = map.split('\n').map(line => [...line]);
const MOVES = {
'^': [0, -1, 'v'],
'>': [1, 0, 'h'],
'v': [0, 1, 'v'],
'<': [-1, 0, 'h']
};
const expansion = {
'#': '##',
'O': '[]',
'.': '..',
'@': '@.'
};
let robot = { x: 0, y: 0 };
map.forEach((line, y) => {
line.forEach((char, x) => {
if (char === "@") {
robot.x = x;
robot.y = y;
}
});
});
const expandedMap = [];
map.forEach(line => {
const row = [];
line.forEach(char => {
row.push(expansion[char][0])
row.push(expansion[char][1])
});
expandedMap.push(row);
});
ins = ins.split('').filter(char => char.trim() !== '');
let toMove = [[robot.x, robot.y]];
ins.forEach(m => {
const move = MOVES[m];
const nx = robot.x + move[0];
const ny = robot.y + move[1];
if (map[ny][nx] === '.') {
map[robot.y][robot.x] = '.';
robot.x = nx;
robot.y = ny;
map[ny][nx] = '@';
} else if (map[ny][nx] === 'O') {
toMove.push([nx, ny]);
let x = nx + move[0];
let y = ny + move[1];
while (map[y][x] === 'O') {
toMove.push([x, y]);
x += move[0];
y += move[1];
}
if (map[y][x] === '.') {
let mx, my;
for (let i = toMove.length - 1; i >= 0; i--) {
mx = toMove[i][0];
my = toMove[i][1];
map[y][x] = map[my][mx];
x = mx;
y = my;
}
map[robot.y][robot.x] = '.';
robot.x = nx;
robot.y = ny;
}
toMove = [[robot.x, robot.y]];
}
});
let r1 = 0;
map.forEach((line, y) => {
line.forEach((char, x) => {
if (char === "O") {
r1 += 100 * y + x;
}
});
});
console.log('Part 1 ->', r1);
expandedMap.forEach((line, y) => {
line.forEach((char, x) => {
if (char === "@") {
robot.x = x;
robot.y = y;
}
});
});
toMove = [[robot.x, robot.y]];
let v;
ins.forEach(m => {
const move = MOVES[m];
const nx = robot.x + move[0];
const ny = robot.y + move[1];
if (expandedMap[ny][nx] === '.') {
expandedMap[robot.y][robot.x] = '.';
robot.x = nx;
robot.y = ny;
expandedMap[ny][nx] = '@';
} else if (expandedMap[ny][nx] === ']' && move[2] === 'h') {
toMove = [[robot.x, robot.y]];
v = new Set();
toMove.push([nx, ny]);
toMove.push([nx-1, ny]);
v.add(`${nx-1},${ny}`);
let x = nx + move[0];
let y = ny + move[1];
while (expandedMap[y][x] === '[' || expandedMap[y][x] === ']') {
if (!v.has(`${x},${y}`)) {
toMove.push([x, y]);
v.add(`${x},${y}`)
}
x += move[0];
y += move[1];
}
if (expandedMap[y][x] === '.') {
let mx, my;
for (let i = toMove.length - 1; i >= 0; i--) {
mx = toMove[i][0];
my = toMove[i][1];
expandedMap[y][x] = expandedMap[my][mx];
x = mx;
y = my;
}
expandedMap[robot.y][robot.x] = '.';
robot.x = nx;
robot.y = ny;
}
toMove = [[robot.x, robot.y]];
} else if (expandedMap[ny][nx] === '[' && move[2] === 'h') {
toMove = [[robot.x, robot.y]];
v = new Set();
toMove.push([nx, ny]);
toMove.push([nx+1, ny]);
v.add(`${nx+1},${ny}`);
let x = nx + move[0];
let y = ny + move[1];
while (expandedMap[y][x] === '[' || expandedMap[y][x] === ']') {
if (!v.has(`${x},${y}`)) {
toMove.push([x, y]);
v.add(`${x},${y}`)
}
x += move[0];
y += move[1];
}
if (expandedMap[y][x] === '.') {
let mx, my;
for (let i = toMove.length - 1; i >= 0; i--) {
mx = toMove[i][0];
my = toMove[i][1];
expandedMap[y][x] = expandedMap[my][mx];
x = mx;
y = my;
}
expandedMap[robot.y][robot.x] = '.';
robot.x = nx;
robot.y = ny;
}
toMove = [[robot.x, robot.y]];
} else if ((expandedMap[ny][nx] === ']' || expandedMap[ny][nx] === '[') && move[2] === 'v') {
toMove = [[robot.x, robot.y]];
v = new Set();
if (expandedMap[ny][nx] === ']') {
toMove.push([nx-1, ny]);
v.add(`${nx-1},${ny}`);
toMove.push([nx, ny]);
v.add(`${nx},${ny}`);
let parts = [[nx-1,ny],[nx,ny]];
checkBoxes(parts, m);
} else {
toMove.push([nx, ny]);
v.add(`${nx},${ny}`);
toMove.push([nx+1, ny]);
v.add(`${nx+1},${ny}`);
let parts = [[nx,ny],[nx+1,ny]];
checkBoxes(parts, m);
}
if (toMove.length > 0) {
toMove = orderCoords(toMove);
let mx, my;
let tx, ty;
for (let i = toMove.length - 1; i >= 0; i--) {
mx = toMove[i][0];
my = toMove[i][1];
tx = mx + MOVES[m][0];
ty = my + MOVES[m][1];
expandedMap[ty][tx] = expandedMap[my][mx];
expandedMap[my][mx] = '.';
tx = mx;
ty = my;
}
robot.x = tx + MOVES[m][0];
robot.y = ty + MOVES[m][1];
}
toMove = [[robot.x, robot.y]];
}
});
let r2 = 0;
expandedMap.forEach((line, y) => {
line.forEach((char, x) => {
if (char === "[") {
r2 += 100 * y + x;
}
});
});
console.log('Part 2 ->', r2);
function checkBoxes(parts, m) {
for (let part of parts) {
const x = part[0] + MOVES[m][0];
const y = part[1] + MOVES[m][1];
if (expandedMap[y][x] === '#') {
toMove = [];
return false;
}
else if (expandedMap[y][x] === '[') {
if (!v.has(`${x},${y}`)) {
toMove.push([x,y]);
v.add(`${x},${y}`);
toMove.push([x+1,y]);
v.add(`${x+1},${y}`);
}
if (!checkBoxes([[x,y],[x+1,y]], m)) {
return false;
}
} else if (expandedMap[y][x] === ']') {
if (!v.has(`${x},${y}`)) {
toMove.push([x-1,y]);
v.add(`${x-1},${y}`);
toMove.push([x,y]);
v.add(`${x},${y}`);
}
if (!checkBoxes([[x-1,y],[x,y]], m)) {
return false;
}
}
}
return true;
}
function orderCoords(coords) {
const sortDirection = coords[1][1] < coords[0][1] ? 'desc' : 'asc';
coords.sort((a, b) => {
if (sortDirection === 'desc') {
return b[1] - a[1] || a[0] - b[0];
} else {
return a[1] - b[1] || a[0] - b[0];
}
});
return coords;
}
Language:JavaScript