Public
Edited
Dec 2
Paused
1 fork
1 star
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
directions = ({
"|": [
[-1, 0],
[1, 0]
],
"-": [
[0, -1],
[0, 1]
],
L: [
[-1, 0],
[0, 1]
],
J: [
[-1, 0],
[0, -1]
],
"7": [
[1, 0],
[0, -1]
],
F: [
[1, 0],
[0, 1]
]
})
Insert cell
Insert cell
function parse(input) {
const toId = (r, c) => `${r},${c}`;
const fromId = (id) => id.split(",").map(Number);
const g = new Graph();
const grid = input.split("\n").map((row) => row.split(""));
const [nRows, nCols] = [grid.length, grid[0].length];
let start;
for (let row = 0; row < nRows; row++) {
for (let col = 0; col < nCols; col++) {
const cellType = grid[row][col];
if (cellType in directions) {
directions[cellType].forEach(([dr, dc]) => {
const [r2, c2] = [row + dr, col + dc];
if (r2 >= 0 && r2 < nRows && c2 >= 0 && c2 < nCols) {
g.addEdge(toId(row, col), toId(r2, c2));
}
});
} else if (cellType === "S") {
start = toId(row, col);
}
}
}
// Store type of pipe under the start position.
const determineStartPipeType = (grid, [r0, c0], [r1, c1], [r2, c2]) => {
const isRowGreater = Math.max(r1, r2) > r0;
const isColGreater = Math.max(c1, c2) > c0;
const isColLesser = Math.min(c1, c2) < c0;
if (isRowGreater) {
return isColGreater ? "F" : isColLesser ? "7" : "|";
}
if (Math.min(r1, r2) < r0) {
return isColGreater ? "L" : "J";
}
return "-";
};

const [n1, n2] = g.inNodes(start);
g.addEdge(start, n1);
g.addEdge(start, n2);
grid[fromId(start)[0]][fromId(start)[1]] = determineStartPipeType(
grid,
fromId(start),
fromId(n1),
fromId(n2)
);

return { start, graph: g, grid };
}
Insert cell
Insert cell
function findMaxDist(maze) {
const [queue, visited] = [[[maze.start, 0]], new Set()];
visited.add(maze.start);
let maxSteps = 0;
while (queue.length > 0) {
let [currentNode, currentDistance] = queue.shift();
maxSteps = Math.max(maxSteps, currentDistance);

for (const neighbour of maze.graph.adjacent(currentNode)) {
if (!visited.has(neighbour)) {
visited.add(neighbour);
queue.push([neighbour, currentDistance + 1]);
}
}
}
return maxSteps;
}
Insert cell
function part1(input) {
return findMaxDist(parse(input));
}
Insert cell
Insert cell
Insert cell
Insert cell
function crossings(row, col, grid) {
return grid[row].slice(col).filter((c) => c === "|" || c === "L" || c === "J")
.length;
}
Insert cell
Insert cell
function findNests(maze) {
const loop = maze.graph
.breadthFirstSearch(maze.start)
.map((id) => id.split(",").map(Number));
const grid = Array(maze.grid.length)
.fill()
.map(() => Array(maze.grid[0].length).fill("."));
for (const [r, c] of loop) {
grid[r][c] = maze.grid[r][c];
}

let numNestCells = 0;
for (let row = 0; row < maze.grid.length; row++) {
for (let col = 0; col < maze.grid[0].length; col++) {
if (grid[row][col] === ".") {
numNestCells += crossings(row, col, grid) % 2 === 0 ? 0 : 1;
}
}
}
return numNestCells;
}
Insert cell
function part2(input) {
return findNests(parse(input));
}
Insert cell
Insert cell
Type JavaScript, then Shift-Enter. Ctrl-space for more options. Arrow ↑/↓ to switch modes.

Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more