Public
Edited
Dec 6, 2023
Insert cell
Insert cell
Insert cell
function parse(input) {
const [seedInput, ...mapInputs] = input.split("\n\n");
const parseMap = (mapInput) =>
mapInput
.split("\n")
.slice(1)
.map((line) => line.split(/\s+/).map(Number))
.sort(([aTo, aFrom], [bTo, bFrom]) => aFrom - bFrom)
.map(([to, from, range]) => ({
range: [from, from + range - 1],
offset: to - from
}));

return {
seeds: seedInput.split(/\s+/).slice(1).map(Number),
maps: mapInputs.map(parseMap)
};
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
function grow(seed, almanac) {
const inRange = (n, [rMin, rMax]) => rMin <= n && n <= rMax;
let val = seed;
for (const map of almanac.maps) {
for (const transform of map) {
if (inRange(val, transform.range)) {
val += transform.offset;
break;
}
}
}
return val;
}
Insert cell
Insert cell
function part1(input) {
const almanac = parse(input);
return Math.min(...almanac.seeds.map((s) => grow(s, almanac)));
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
function splitRange(seedRange, transformRanges) {
let remainingRange = [...seedRange];
let splitRanges = [];

for (const transform of transformRanges) {
if (remainingRange[0] > transform.range[1]) {
continue;
}
if (remainingRange[1] < transform.range[0]) {
splitRanges.push(remainingRange);
return splitRanges;
}
if (remainingRange[0] < transform.range[0]) {
splitRanges.push([remainingRange[0], transform.range[0] - 1]);
remainingRange[0] = transform.range[0];
}
if (remainingRange[1] > transform.range[1]) {
splitRanges.push([remainingRange[0], transform.range[1], transform]);
remainingRange[0] = transform.range[1] + 1;
continue;
}
splitRanges.push([...remainingRange, transform]);
return splitRanges;
}

splitRanges.push(remainingRange);
return splitRanges;
}
Insert cell
Insert cell
function transformRange(seedRange, almanac) {
let transformedRanges = [seedRange];

for (const map of almanac.maps) {
let next = [];
for (const range of transformedRanges) {
const splitRanges = splitRange(range, map);
for (const splitRange of splitRanges) {
if (splitRange.length > 2) {
const [start, end, transform] = splitRange;
next.push([start + transform.offset, end + transform.offset]);
} else {
next.push(splitRange);
}
}
}
transformedRanges = next;
}
return transformedRanges;
}
Insert cell
Insert cell
function lowestLocation(almanac) {
let lowestLocation = Infinity;
for (const seedRange of almanac.seeds) {
for (const range of transformRange(seedRange, almanac)) {
lowestLocation = Math.min(lowestLocation, range[0]);
}
}
return lowestLocation;
}
Insert cell
Insert cell
function part2(input) {
const almanac = parse(input);
almanac.seeds = AOC.chunk(almanac.seeds, 2).map(([lower, range]) => [
lower,
lower + range - 1
]);
return lowestLocation(almanac);
}
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