-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #234 from romellem/2024/day-8
2024 - Day 8
- Loading branch information
Showing
8 changed files
with
439 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
# Answers | ||
|
||
| Part 1 | Part 2 | | ||
| ------ | ------ | | ||
| `336` | `1131` | | ||
|
||
## --- Day 8: Resonant Collinearity --- | ||
|
||
You find yourselves on the [roof](https://adventofcode.com/2016/day/25) of a top-secret Easter Bunny installation. | ||
|
||
While The Historians do their thing, you take a look at the familiar _huge antenna_. Much to your surprise, it seems to have been reconfigured to emit a signal that makes people 0.1% more likely to buy Easter Bunny brand Imitation Mediocre Chocolate as a Christmas gift! Unthinkable! | ||
|
||
Scanning across the city, you find that there are actually many such antennas. Each antenna is tuned to a specific _frequency_ indicated by a single lowercase letter, uppercase letter, or digit. You create a map (your puzzle input) of these antennas. For example: | ||
|
||
............ | ||
........0... | ||
.....0...... | ||
.......0.... | ||
....0....... | ||
......A..... | ||
............ | ||
............ | ||
........A... | ||
.........A.. | ||
............ | ||
............ | ||
|
||
|
||
The signal only applies its nefarious effect at specific _antinodes_ based on the resonant frequencies of the antennas. In particular, an antinode occurs at any point that is perfectly in line with two antennas of the same frequency - but only when one of the antennas is twice as far away as the other. This means that for any pair of antennas with the same frequency, there are two antinodes, one on either side of them. | ||
|
||
So, for these two antennas with frequency `a`, they create the two antinodes marked with `#`: | ||
|
||
.......... | ||
...#...... | ||
.......... | ||
....a..... | ||
.......... | ||
.....a.... | ||
.......... | ||
......#... | ||
.......... | ||
.......... | ||
|
||
|
||
Adding a third antenna with the same frequency creates several more antinodes. It would ideally add four antinodes, but two are off the right side of the map, so instead it adds only two: | ||
|
||
.......... | ||
...#...... | ||
#......... | ||
....a..... | ||
........a. | ||
.....a.... | ||
..#....... | ||
......#... | ||
.......... | ||
.......... | ||
|
||
|
||
Antennas with different frequencies don't create antinodes; `A` and `a` count as different frequencies. However, antinodes _can_ occur at locations that contain antennas. In this diagram, the lone antenna with frequency capital `A` creates no antinodes but has a lowercase-`a`\-frequency antinode at its location: | ||
|
||
.......... | ||
...#...... | ||
#......... | ||
....a..... | ||
........a. | ||
.....a.... | ||
..#....... | ||
......A... | ||
.......... | ||
.......... | ||
|
||
|
||
The first example has antennas with two different frequencies, so the antinodes they create look like this, plus an antinode overlapping the topmost `A`\-frequency antenna: | ||
|
||
......#....# | ||
...#....0... | ||
....#0....#. | ||
..#....0.... | ||
....0....#.. | ||
.#....A..... | ||
...#........ | ||
#......#.... | ||
........A... | ||
.........A.. | ||
..........#. | ||
..........#. | ||
|
||
|
||
Because the topmost `A`\-frequency antenna overlaps with a `0`\-frequency antinode, there are _`14`_ total unique locations that contain an antinode within the bounds of the map. | ||
|
||
Calculate the impact of the signal. _How many unique locations within the bounds of the map contain an antinode?_ | ||
|
||
----------------- | ||
|
||
## --- Part Two --- | ||
|
||
Watching over your shoulder as you work, one of The Historians asks if you took the effects of resonant harmonics into your calculations. | ||
|
||
Whoops! | ||
|
||
After updating your model, it turns out that an antinode occurs at _any grid position_ exactly in line with at least two antennas of the same frequency, regardless of distance. This means that some of the new antinodes will occur at the position of each antenna (unless that antenna is the only one of its frequency). | ||
|
||
So, these three `T`\-frequency antennas now create many antinodes: | ||
|
||
T....#.... | ||
...T...... | ||
.T....#... | ||
.........# | ||
..#....... | ||
.......... | ||
...#...... | ||
.......... | ||
....#..... | ||
.......... | ||
|
||
|
||
In fact, the three `T`\-frequency antennas are all exactly in line with two antennas, so they are all also antinodes! This brings the total number of antinodes in the above example to _`9`_. | ||
|
||
The original example now has _`34`_ antinodes, including the antinodes that appear on every antenna: | ||
|
||
##....#....# | ||
.#.#....0... | ||
..#.#0....#. | ||
..##...0.... | ||
....0....#.. | ||
.#...#A....# | ||
...#..#..... | ||
#....#.#.... | ||
..#.....A... | ||
....#....A.. | ||
.#........#. | ||
...#......## | ||
|
||
|
||
Calculate the impact of the signal using this updated model. _How many unique locations within the bounds of the map contain an antinode?_ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import path from 'path'; | ||
import fs from 'fs'; | ||
|
||
export const input: Array<Array<string>> = fs | ||
.readFileSync(path.join(import.meta.dirname, 'input.txt'), 'utf8') | ||
.toString() | ||
.trim() | ||
.split('\n') | ||
.map((line, y) => { | ||
return line.split(''); | ||
}); | ||
|
||
export const sampleInput: Array<Array<string>> = fs | ||
.readFileSync(path.join(import.meta.dirname, 'sample-input.txt'), 'utf8') | ||
.toString() | ||
.trim() | ||
.split('\n') | ||
.map((line, y) => { | ||
return line.split(''); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
.................................................. | ||
.......................x.................N........ | ||
..................x............................... | ||
............x................w.........D.....a.... | ||
.........6...........i.........D..............u... | ||
........6.......................q................u | ||
........................i....u.w...........a.2.... | ||
....................................u.12.......... | ||
..................................f.....D....0a... | ||
.............................Q..D......c..N..f.... | ||
..............w..................................f | ||
.........Y.............i...............q..a....... | ||
............................2..........O...q...... | ||
.....6..G.....................R................... | ||
..............................N................... | ||
.U.......G................i...J.............0..... | ||
Y..U................F......N...................... | ||
.T......Y.............H.................2.P....... | ||
...............T.........F.8........H............. | ||
..T...............F...............l..............0 | ||
................G.....e........18...Q............. | ||
.......................F....................O..... | ||
.....Y....U...................l....g.............. | ||
U........9........................................ | ||
.....................e..q..Q...................... | ||
.......X........e......................1Q..O...... | ||
............T.................gx......0..........t | ||
...................l......9........P.............. | ||
.y...........9...............r.5.......j.P........ | ||
..z.........d.........g......................H.... | ||
................6.......r...........P.........O... | ||
.A........................8...r................... | ||
.4....W...Z...........9..................s..j..... | ||
.z..W.........y...........og...................... | ||
..3.z.....R.....L....o.........................H.. | ||
.......yZ.c..W.......p..............s............. | ||
............1..3.........L.........S.............. | ||
.......Z..4............o.....S...........5.......s | ||
............c........l......7..................... | ||
.....4....p.........I.......t...........5........j | ||
.......c....h...........C..d...................... | ||
......n..........C......L............E....j....... | ||
.X.W..........n....R......d.I...............5..... | ||
3.........Cn.........L...r.............e.......... | ||
...A...........Z.p.....I..S.............s.......J. | ||
....................7.............S...X....J...... | ||
........X.............o........................... | ||
........A....h.R.....7.t...I...................... | ||
..A.4z......y.p..h.7...........Et................. | ||
................h........3..E..d.8................ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
import G from 'generatorics'; | ||
|
||
import { input } from './input'; | ||
|
||
type Point = { | ||
x: number; | ||
y: number; | ||
char: string; | ||
}; | ||
|
||
type Antinode = { | ||
x: number; | ||
y: number; | ||
}; | ||
|
||
type Vect = { | ||
dx: number; | ||
dy: number; | ||
}; | ||
|
||
const points: Array<Point> = input | ||
.map((line, y) => { | ||
return line.map((char, x) => { | ||
return { | ||
char, | ||
x, | ||
y, | ||
}; | ||
}); | ||
}) | ||
.flat(); | ||
|
||
const maxX = input[0].length; | ||
const maxY = input.length; | ||
|
||
function inBounds(x: number, y: number): boolean { | ||
return x >= 0 && x < maxX && y >= 0 && y < maxY; | ||
} | ||
|
||
function shift(antinode: Readonly<Antinode>, vec: Readonly<Vect>): Antinode { | ||
return { x: antinode.x + vec.dx, y: antinode.y + vec.dy }; | ||
} | ||
|
||
/** | ||
* Use singleton pattern for antinodes so they can dedupe within our Set. | ||
* Antinodes aren't unique by frequency types, just coordinates. That is, | ||
* two antennas might create an antinode at the same location, but only | ||
* a single antinode should be present. | ||
*/ | ||
const antinodeCache = new Map<string, Antinode>(); | ||
function getAntinode(x: number, y: number): Antinode { | ||
const key = `${x},${y}`; | ||
if (!antinodeCache.has(key)) { | ||
antinodeCache.set(key, { x, y }); | ||
} | ||
return antinodeCache.get(key)!; | ||
} | ||
|
||
// Group antennas by its frequency type | ||
const antennas = points.filter((point) => point.char !== '.'); | ||
const groups = new Map<string, Array<Point>>(); | ||
for (let antenna of antennas) { | ||
if (!groups.has(antenna.char)) { | ||
groups.set(antenna.char, []); | ||
} | ||
groups.get(antenna.char)!.push(antenna); | ||
} | ||
|
||
const uniqueAntennaFrequencies = Array.from(groups.keys()); | ||
|
||
const antinodes = new Set<Antinode>(); | ||
|
||
for (let antennaFrequency of uniqueAntennaFrequencies) { | ||
const listOfAntennas = groups.get(antennaFrequency)!; | ||
|
||
// If there's only 1 antenna of this frequency, not antinodes can be formed (no pairs can be created) | ||
if (listOfAntennas.length < 2) { | ||
continue; | ||
} | ||
|
||
for (let antennaPair of G.combination(listOfAntennas, 2)) { | ||
const [antennaA, antennaB] = antennaPair; | ||
|
||
// Calculate vectors between the two antennas. aToB == -1 * bToA | ||
const aToB: Vect = { dx: antennaB.x - antennaA.x, dy: antennaB.y - antennaA.y }; | ||
const bToA: Vect = { dx: antennaA.x - antennaB.x, dy: antennaA.y - antennaB.y }; | ||
|
||
// Continue adding the vector to create new antinodes until we are out of bounds | ||
const antinodeA: Antinode = shift(antennaA, bToA); | ||
if (inBounds(antinodeA.x, antinodeA.y)) { | ||
antinodes.add(getAntinode(antinodeA.x, antinodeA.y)); | ||
} | ||
|
||
// Do the same but in the other direction | ||
const antinodeB: Antinode = shift(antennaB, aToB); | ||
if (inBounds(antinodeB.x, antinodeB.y)) { | ||
antinodes.add(getAntinode(antinodeB.x, antinodeB.y)); | ||
} | ||
} | ||
} | ||
|
||
console.log(antinodes.size); |
Oops, something went wrong.