diff --git a/.github/badges/completion.json b/.github/badges/completion.json index a01e63a..7180bd4 100644 --- a/.github/badges/completion.json +++ b/.github/badges/completion.json @@ -1,6 +1,6 @@ { "schemaVersion": 1, "label": "completion", - "message": "20/50", + "message": "22/50", "color": "yellow" } diff --git a/README.md b/README.md index 97887f7..b7f06f7 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ Collect stars by solving puzzles. Two puzzles will be made available on each day - [Day 8: Haunted Wasteland](day-08-haunted-wasteland/) - [Day 9: Mirage Maintenance](day-09-mirage-maintenance/) - [Day 10: Pipe Maze](day-10-pipe-maze/) -- [Day 11: TBD](day-11/) +- [Day 11: Cosmic Expansion](day-11-cosmic-expansion/) - [Day 12: TBD](day-12/) - [Day 13: TBD](day-13/) - [Day 14: TBD](day-14/) diff --git a/day-11-cosmic-expansion/README.md b/day-11-cosmic-expansion/README.md new file mode 100644 index 0000000..20966e6 --- /dev/null +++ b/day-11-cosmic-expansion/README.md @@ -0,0 +1,114 @@ +# Day 11: Cosmic Expansion + +You continue following signs for "Hot Springs" and eventually come across an [observatory](https://en.wikipedia.org/wiki/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?** + +## Part Two + +The galaxies are much **older** (and thus much **farther apart**) than the researcher initially estimated. + +Now, instead of the expansion you did before, make each empty row or column **one million times** larger. That is, each empty row should be replaced with `1000000` empty rows, and each empty column should be replaced with `1000000` empty columns. + +(In the example above, if each empty row or column were merely `10` times larger, the sum of the shortest paths between every pair of galaxies would be **`1030`**. If each empty row or column were merely `100` times larger, the sum of the shortest paths between every pair of galaxies would be **`8410`**. However, your universe will need to expand far beyond these values.) + +Starting with the same initial image, expand the universe according to these new rules, then find the length of the shortest path between every pair of galaxies. **What is the sum of these lengths?** + +## References +- https://adventofcode.com/2023/day/11 diff --git a/day-11-cosmic-expansion/part1.js b/day-11-cosmic-expansion/part1.js new file mode 100644 index 0000000..96911b9 --- /dev/null +++ b/day-11-cosmic-expansion/part1.js @@ -0,0 +1,48 @@ +module.exports = (input, expansion = 2) => { + const seamsX = []; + const seamsY = []; + const galaxies = []; + + const universe = input.split('\n').reduce((u, line, y) => { + const content = line.trim().split(''); + + for (let x = 0; x < content.length; x++) { + if (content[x] === '#') { + galaxies.push([x, y]); + } + } + + if (content.every((item) => item === '.')) { + seamsY.push(y); + } + + u.push(content); + + return u; + }, []); + + for (let x = 0; x < universe[0].length; x++) { + const seam = universe.map((line) => line[x]); + + if (seam.every((item) => item === '.')) { + seamsX.push(x); + } + } + + return galaxies + .reduce((pairs, galaxy, i) => [ + ...pairs, + ...galaxies.slice(i + 1).map((other) => { + return [galaxy, other]; + }), + ], []) + .reduce((sum, [g1, g2]) => { + const f = expansion - 1; + const x1 = seamsX.filter((seam) => seam <= g1[0]).length * f + g1[0]; + const y1 = seamsY.filter((seam) => seam <= g1[1]).length * f + g1[1]; + const x2 = seamsX.filter((seam) => seam <= g2[0]).length * f + g2[0]; + const y2 = seamsY.filter((seam) => seam <= g2[1]).length * f + g2[1]; + + return sum + Math.abs(x1 - x2) + Math.abs(y1 - y2); + }, 0); +}; diff --git a/day-11-cosmic-expansion/part2.js b/day-11-cosmic-expansion/part2.js new file mode 100644 index 0000000..3f6f040 --- /dev/null +++ b/day-11-cosmic-expansion/part2.js @@ -0,0 +1,3 @@ +const expansion = require('./part1'); + +module.exports = (input) => expansion(input, 1_000_000); diff --git a/day-11-cosmic-expansion/test.js b/day-11-cosmic-expansion/test.js new file mode 100644 index 0000000..62afb23 --- /dev/null +++ b/day-11-cosmic-expansion/test.js @@ -0,0 +1,40 @@ +const assert = require('node:assert'); + +const part1 = require('./part1'); +const part2 = require('./part2'); + +describe('Day 11: Cosmic Expansion', () => { + it('should sum galaxy distances', () => { + const input = + `...#...... + .......#.. + #......... + .......... + ......#... + .#........ + .........# + .......... + .......#.. + #...#.....`; + + assert.strictEqual(part1(input), 374); + }); + + describe('Part Two', () => { + it('should sum distances with 100x expansion', () => { + const input = + `...#...... + .......#.. + #......... + .......... + ......#... + .#........ + .........# + .......... + .......#.. + #...#.....`; + + assert.strictEqual(part2(input, 100), 8410); + }); + }); +});