advent of code 2023 day 11: cutting corners while discovering galaxies

This commit is contained in:
Wouter Groeneveld 2023-12-11 15:00:18 +01:00
parent 14bee85b0c
commit 9a7148770e
3 changed files with 173 additions and 0 deletions

96
2023/11/assignment.md Normal file
View File

@ -0,0 +1,96 @@
# --- Day 11: Cosmic Expansion ---
You continue following signs for "Hot Springs" and eventually come across an observatory. The Elf within turns out to be a researcher studying cosmic expansion using the giant telescope here.
He doesn't know anything about the missing machine parts; he's only visiting for this research project. However, he confirms that the hot springs are the next-closest area likely to have people; he'll even take you straight there once he's done with today's observation analysis.
Maybe you can help him with the analysis to speed things up?
The researcher has collected a bunch of data and compiled the data into a single giant image (your puzzle input). The image includes empty space (.) and galaxies (#). For example:
...#......
.......#..
#.........
..........
......#...
.#........
.........#
..........
.......#..
#...#.....
The researcher is trying to figure out the sum of the lengths of the shortest path between every pair of galaxies. However, there's a catch: the universe expanded in the time it took the light from those galaxies to reach the observatory.
Due to something involving gravitational effects, only some space expands. In fact, the result is that any rows or columns that contain no galaxies should all actually be twice as big.
In the above example, three columns and two rows contain no galaxies:
v v v
...#......
.......#..
#.........
>..........<
......#...
.#........
.........#
>..........<
.......#..
#...#.....
^ ^ ^
These rows and columns need to be twice as big; the result of cosmic expansion therefore looks like this:
....#........
.........#...
#............
.............
.............
........#....
.#...........
............#
.............
.............
.........#...
#....#.......
Equipped with this expanded universe, the shortest path between every pair of galaxies can be found. It can help to assign every galaxy a unique number:
....1........
.........2...
3............
.............
.............
........4....
.5...........
............6
.............
.............
.........7...
8....9.......
In these 9 galaxies, there are 36 pairs. Only count each pair once; order within the pair doesn't matter. For each pair, find any shortest path between the two galaxies using only steps that move up, down, left, or right exactly one . or # at a time. (The shortest path between two galaxies is allowed to pass through another galaxy.)
For example, here is one of the shortest paths between galaxies 5 and 9:
....1........
.........2...
3............
.............
.............
........4....
.5...........
.##.........6
..##.........
...##........
....##...7...
8....9.......
This path has length 9 because it takes a minimum of nine steps to get from galaxy 5 to galaxy 9 (the eight locations marked # plus the step onto galaxy 9 itself). Here are some other example shortest path lengths:
Between galaxy 1 and galaxy 7: 15
Between galaxy 3 and galaxy 6: 17
Between galaxy 8 and galaxy 9: 5
In this example, after expanding the universe, the sum of the shortest path between all 36 pairs of galaxies is 374.
Expand the universe, then find the length of the shortest path between every pair of galaxies. What is the sum of these lengths?

41
2023/11/impl.js Normal file
View File

@ -0,0 +1,41 @@
module.exports.solve = function(input) {
const expandGalaxyInDepth = (map) => {
[...Array(map.length).keys()].forEach(rownr => {
if(new Set(map[rownr]).size === 1 && map[rownr][0] === '.') {
map.splice(rownr, 0, '.'.repeat(map[0].length).split(''))
}
})
return map
}
const expandGalaxyInBreadth = (map) => {
const rownrs = [...Array(map.length).keys()];
[...Array(map[0].length).keys()]
.filter(colnr => new Set(rownrs.map(rownr => map[rownr][colnr])).size === 1 && map[0][colnr] === '.')
.forEach(colnr => {
rownrs.forEach(rownr => {
map[rownr].splice(colnr, 0, '.') // There's something not quite right about this?
})
})
return map
}
const discoverGalaxy = (map) => {
const galaxies = []
// Trying to create these loops functionally here seems to work against me in JS
for(let i = 0; i < map.length; i++) {
for(let j = 0; j < map[i].length; j++) {
if(map[i][j] === '#') {
galaxies.push([i, j])
}
}
}
return galaxies
}
const map = expandGalaxyInBreadth(expandGalaxyInDepth(input.split('\n').map(row => row.split(''))))
const planets = discoverGalaxy(map)
return planets
// Cutting corners: difference in coords = minimum distance. Won't always work?
.flatMap((v, i) => planets.slice(i+1).map(w => Math.abs(v[0] - w[0]) + Math.abs(v[1] - w[1])))
.reduce((a, b) => a + b)
}

36
2023/11/test.js Normal file
View File

@ -0,0 +1,36 @@
const test = require('node:test')
const assert = require('node:assert').strict;
const { readFileSync } = require('fs')
const { solve } = require('./impl.js')
/*
test('The single shortest path in an isolated example is 9', (t) => {
const input = `...x......
.......x..
x.........
..........
......x...
.#........
.........x
..........
.......x..
x...#.....`
assert.equal(9, solve(input))
})
*/
test('The sum of the shortest paths between galaxies in the assignment is 374', (t) => {
const input = `...#......
.......#..
#.........
..........
......#...
.#........
.........#
..........
.......#..
#...#.....`
assert.equal(374, solve(input))
})