Public
Edited
Dec 14, 2022
1 fork
Importers
5 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
frames = Array.from(part2Generator(parse(inputs.real)))
Insert cell
parse = aoc.lines((l) =>
l
.split(/\s*->\s*/g)
.map((d) => d.split(",").map((n) => +n))
.map(([x, y]) => ({ x, y }))
)
Insert cell
function makeGrid(input) {
let rocks = new GridMap();
for (const series of input) {
let cursor = series[0];
rocks.set(cursor, "rock");
for (const next of series.slice(1)) {
let dx = Math.sign(next.x - cursor.x);
let dy = Math.sign(next.y - cursor.y);
while (cursor.x !== next.x || cursor.y !== next.y) {
cursor.x += dx;
cursor.y += dy;
rocks.set(cursor, "rock");
}
}
}
return rocks;
}
Insert cell
sandFrom = ({ x: 500, y: 0 })
Insert cell
function part1(input) {
let grid = makeGrid(input);
let yLimit = d3.max(grid, (d) => d[0].y);
let sandCount = 0;

while (true) {
const sand = { ...sandFrom };
while (true) {
if (!grid.has({ ...sand, y: sand.y + 1 })) sand.y += 1;
else if (!grid.has({ x: sand.x - 1, y: sand.y + 1 })) {
sand.x -= 1;
sand.y += 1;
} else if (!grid.has({ x: sand.x + 1, y: sand.y + 1 })) {
sand.x += 1;
sand.y += 1;
} else {
grid.set(sand, "sand");
sandCount += 1;
break;
}
if (sand.y >= yLimit) {
return sandCount;
}
}
}
}
Insert cell
function* part2Generator(input, skip = 100) {
let grid = makeGrid(input);
yield grid.clone();
let lastSandLevel = d3.max(grid, (d) => d[0].y) + 1;
let sandCount = 0;
let budget = 1e7;

while (budget-- > 0) {
const sand = { ...sandFrom };
while (budget-- > 0) {
let stopped = false;
if (!grid.has({ ...sand, y: sand.y + 1 })) sand.y += 1;
else if (!grid.has({ x: sand.x - 1, y: sand.y + 1 })) {
sand.x -= 1;
sand.y += 1;
} else if (!grid.has({ x: sand.x + 1, y: sand.y + 1 })) {
sand.x += 1;
sand.y += 1;
} else {
stopped = true;
}

if (sand.y >= lastSandLevel) {
stopped = true;
}

if (stopped) {
grid.set(sand, "sand");
if (sand.x === sandFrom.x && sand.y === sandFrom.y) {
yield grid.clone();
return;
}
sandCount += 1;
if (sandCount % skip === 0) yield grid.clone();
break;
}
}
}
console.log("budget exceeded");
}
Insert cell
function part2(input) {
let steps = Array.from(part2Generator(input, Infinity));
let lastGrid = steps.at(-1);
return Array.from(lastGrid).filter((d) => d[1] === "sand").length;
}
Insert cell
class GridMap extends Map {
constructor(iter = []) {
super();
for (const [key, obj] of iter) {
this.set(key, obj);
}
}
_key(idx) {
return `${idx.x},${idx.y}`;
}
get(idx) {
return super.get(this._key(idx));
}
set(idx, val) {
return super.set(this._key(idx), val);
}
has(idx) {
return super.has(this._key(idx));
}
*[Symbol.iterator]() {
for (const [key, value] of super[Symbol.iterator]()) {
let [x, y] = key.split(",").map((d) => +d);
yield [{ x, y }, value];
}
}
clone() {
return new GridMap(this);
}
}
Insert cell
Insert cell
meta = aoc.meta({
day: 14,
parse,
inputs,
parts: [part1, part2],
expected: { test: [24, 93], real: [610, 27194] },
href: "#"
})
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