-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
12 changed files
with
241 additions
and
1 deletion.
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
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,11 @@ | ||
import 'package:aoc_2024/lib.dart'; | ||
import 'package:aoc_2024/day8/part_1.dart' as part1; | ||
import 'package:aoc_2024/day8/part_2.dart' as part2; | ||
|
||
Future<void> main(List<String> arguments) async { | ||
await runDay( | ||
day: 7, | ||
part1: part1.calculate, | ||
part2: part2.calculate, | ||
); | ||
} |
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
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
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,17 @@ | ||
import 'package:aoc_2024/lib.dart'; | ||
|
||
import 'shared.dart'; | ||
|
||
/// Find the number of antinodes from a map of antenna locations. | ||
/// | ||
/// 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 function should return the number of locations on the map that | ||
/// are antinodes (some locations may be antinodes for multiple | ||
/// frequencies, so only count those once). | ||
Future<int> calculate(Resources resources) async { | ||
final frequencyMap = await loadData(resources); | ||
return frequencyMap.antinodes(includeHarmonics: false).length; | ||
} |
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,18 @@ | ||
import 'package:aoc_2024/lib.dart'; | ||
|
||
import 'shared.dart'; | ||
|
||
/// Continuing from part 1, include all harmonics of the frequency | ||
/// when determining the number of antinode locations. | ||
/// | ||
/// This mean including any grid position that is exactly in line with | ||
/// at least two antennas of the same frequency, regardless of distance. | ||
/// It also means that the antenna locations themselves can be considered | ||
/// as antinode locations. | ||
/// | ||
/// Return value is the same as part 1: number of unique locations that | ||
/// are antinodes. | ||
Future<int> calculate(Resources resources) async { | ||
final frequencyMap = await loadData(resources); | ||
return frequencyMap.antinodes(includeHarmonics: true).length; | ||
} |
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,127 @@ | ||
import 'dart:math'; | ||
|
||
import 'package:aoc_2024/lib.dart'; | ||
|
||
typedef Location = Point<int>; | ||
|
||
/// Represents frequencies being broadcast from antennas within a map. | ||
final class FrequencyMap { | ||
/// Map of frequenct to locations with an antenna broadcasting that | ||
/// frequency. | ||
final Map<String, List<Location>> antennaLocations; | ||
|
||
/// Height bound of the map. | ||
final int height; | ||
|
||
/// Width bound of the map. | ||
final int width; | ||
|
||
FrequencyMap( | ||
{required this.antennaLocations, | ||
required this.height, | ||
required this.width}); | ||
|
||
/// Returns true if the given location fits within the bounds of | ||
/// the map. | ||
bool inBounds(final Location location) { | ||
return location.x >= 0 && | ||
location.x < height && | ||
location.y >= 0 && | ||
location.y < width; | ||
} | ||
|
||
/// Generates a list of all antinodes for this map. Antinodes are points | ||
/// in which the broadcast from two antennas of the same frequency are | ||
/// amplified. | ||
/// | ||
/// If [includeHarmonics] is false, this will generate two antinodes per | ||
/// pair of antennas on the same frequency. The antinodes will be on either | ||
/// side of each antenna, where one antinode is twice as far from one antenna. | ||
/// | ||
/// If [includeHarmonics] is true, this will generate all antinodes along the | ||
/// straightline path between two antennas. Each antinode is spaced out | ||
/// according to the distance between the two antennas. | ||
Set<Location> antinodes({bool includeHarmonics = false}) { | ||
Set<Location> antinodes = {}; | ||
|
||
for (final antennaLocations in antennaLocations.values) { | ||
for (final pair in pairs(antennaLocations)) { | ||
antinodes.addAll(_generateAntinodesUntilOutOfBounds( | ||
a: pair.$1, b: pair.$2, includeHarmonics: includeHarmonics)); | ||
} | ||
} | ||
|
||
return antinodes; | ||
} | ||
|
||
/// Generates the list of antinodes for a single pair of antenna locations. | ||
/// See [antinodes] for a description of the generation. | ||
Set<Location> _generateAntinodesUntilOutOfBounds( | ||
{required Location a, | ||
required Location b, | ||
required bool includeHarmonics}) { | ||
final hop = a - b; | ||
Set<Location> locations = {}; | ||
|
||
final List<({Location starting, Location Function(Location) hopFunc})> | ||
directionFunctions = [ | ||
(starting: a, hopFunc: (l) => l + hop), | ||
(starting: a, hopFunc: (l) => l - hop), | ||
(starting: b, hopFunc: (l) => l + hop), | ||
(starting: b, hopFunc: (l) => l - hop), | ||
]; | ||
|
||
for (final direction in directionFunctions) { | ||
var addedOneAntinode = false; | ||
var next = direction.hopFunc(direction.starting); | ||
while ( | ||
// If not including all harmonics, only process this loop until | ||
// an antinode has been added. | ||
(includeHarmonics || !addedOneAntinode) && | ||
// The two antenna locations themselves are only eligible to | ||
// be considered antinodes when including all harmonics. | ||
(includeHarmonics || (next != a && next != b)) && | ||
// Stop processing when encountering an out-of-bounds | ||
// location. | ||
inBounds(next) && | ||
// If a location has already been seen, we can stop processing. | ||
// This is because [directionFunctions] will attempt to process | ||
// each direction from both antenna locations. This allows us to | ||
// avoid figuring out which direction to travel from a given | ||
// antenna, but avoid processing the same locations twice. | ||
!locations.contains(next)) { | ||
locations.add(next); | ||
addedOneAntinode = true; | ||
next = direction.hopFunc(next); | ||
} | ||
} | ||
|
||
return locations; | ||
} | ||
} | ||
|
||
/// Loads data from file, which is a map of frequency to | ||
/// locations (points on a map). | ||
Future<FrequencyMap> loadData(Resources resources) async { | ||
final file = resources.file(Day.day8); | ||
final lines = await file.readAsLines(); | ||
|
||
Map<String, List<Location>> frequencies = {}; | ||
|
||
for (int r = 0; r < lines.length; r++) { | ||
final line = lines[r]; | ||
for (int c = 0; c < line.length; c++) { | ||
if (line[c] == '.') { | ||
continue; | ||
} | ||
|
||
final frequency = frequencies.putIfAbsent(line[c], () => []); | ||
frequency.add(Location(r, c)); | ||
} | ||
} | ||
|
||
return FrequencyMap( | ||
antennaLocations: frequencies, | ||
height: lines.length, | ||
width: lines[0].length); | ||
} |
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 |
---|---|---|
@@ -1,2 +1,3 @@ | ||
export 'shared/resources.dart'; | ||
export 'shared/runner.dart'; | ||
export 'shared/utils.dart'; |
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
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,9 @@ | ||
List<(T, T)> pairs<T>(List<T> items) { | ||
List<(T, T)> records = []; | ||
for (int i = 0; i < items.length - 1; i++) { | ||
for (int j = i + 1; j < items.length; j++) { | ||
records.add((items[i], items[j])); | ||
} | ||
} | ||
return records; | ||
} |
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,12 @@ | ||
............ | ||
........0... | ||
.....0...... | ||
.......0.... | ||
....0....... | ||
......A..... | ||
............ | ||
............ | ||
........A... | ||
.........A.. | ||
............ | ||
............ |
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,30 @@ | ||
import 'package:aoc_2024/lib.dart'; | ||
import 'package:aoc_2024/day8/part_1.dart' as part1; | ||
import 'package:aoc_2024/day8/part_2.dart' as part2; | ||
import 'package:test/test.dart'; | ||
|
||
void main() { | ||
group('sample data', tags: 'sample-data', () { | ||
final resources = Resources.sample; | ||
|
||
test('part1', () async { | ||
expect(await part1.calculate(resources), 14); | ||
}); | ||
|
||
test('part2', () async { | ||
expect(await part2.calculate(resources), 34); | ||
}); | ||
}); | ||
|
||
group('real data', tags: 'real-data', () { | ||
final resources = Resources.real; | ||
|
||
test('part1', () async { | ||
expect(await part1.calculate(resources), 394); | ||
}); | ||
|
||
test('part2', () async { | ||
expect(await part2.calculate(resources), 1277); | ||
}); | ||
}); | ||
} |