Skip to content

Commit 9ca5b6c

Browse files
author
Christian Lundh
committed
C++23 2024 day 8 (python translation)
1 parent b001ee1 commit 9ca5b6c

File tree

3 files changed

+175
-1
lines changed

3 files changed

+175
-1
lines changed

C++/2024/aoc_2024_08.cpp

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
#include "aoc_io.hpp"
2+
#include "aoc_string.hpp"
3+
#include "aoc_timer.hpp"
4+
#include <algorithm>
5+
#include <array>
6+
#include <cmath>
7+
#include <cstdlib>
8+
#include <execution>
9+
#include <functional>
10+
#include <numeric>
11+
#include <ranges>
12+
#include <string>
13+
#include <unordered_map>
14+
#include <unordered_set>
15+
#include <utility>
16+
#include <vector>
17+
18+
template <>
19+
struct std::hash<std::pair<int, int>> {
20+
auto operator()(const pair<int, int> &v) const -> size_t {
21+
return std::size_t(v.first) << 32 | v.second;
22+
}
23+
};
24+
25+
struct Itertools {
26+
public:
27+
template <class T>
28+
static auto combinations(const T &iterable, int repeat) -> std::vector<T> {
29+
auto n = int(iterable.size());
30+
if (repeat > n) {
31+
return std::vector<T>{};
32+
}
33+
auto combo = std::vector<T>{};
34+
auto indices = std::ranges::iota_view(0, repeat) | std::ranges::to<std::vector>();
35+
combo.push_back(T(iterable.begin(), iterable.begin() + repeat));
36+
bool loop_ok = true;
37+
while (loop_ok) {
38+
int i{};
39+
bool nobreak = true;
40+
for (auto ii : std::views::iota(0, repeat) | std::views::reverse) {
41+
if (indices[ii] != ii + n - repeat) {
42+
i = ii;
43+
nobreak = false;
44+
break;
45+
}
46+
}
47+
if (nobreak) {
48+
loop_ok = false;
49+
break;
50+
}
51+
indices[i] += 1;
52+
for (auto jj : std::views::iota(i + 1, int(repeat))) {
53+
indices[jj] = indices[jj - 1] + 1;
54+
}
55+
auto tmp = T{};
56+
for (auto index : indices) {
57+
tmp.push_back(iterable[index]);
58+
}
59+
combo.emplace_back(tmp);
60+
}
61+
return combo;
62+
}
63+
};
64+
65+
using Antenna = std::unordered_map<char, std::vector<std::pair<int, int>>>;
66+
67+
auto parse_instructions(const std::vector<std::string> &instructions) -> std::pair<Antenna, std::pair<int, int>> {
68+
auto antennas = Antenna{};
69+
auto limits = std::pair<int, int>{instructions.size(), instructions.front().size()};
70+
for (auto [row, line] : std::ranges::zip_view(std::ranges::iota_view(0), instructions)) {
71+
for (auto [col, token] : std::ranges::zip_view(std::ranges::iota_view(0), line)) {
72+
if (token != '.') {
73+
antennas[token].emplace_back(row, col);
74+
}
75+
}
76+
}
77+
78+
return {antennas, limits};
79+
}
80+
81+
bool in_bound(auto &node, auto &limits) {
82+
if ((node.first < 0) || (node.first >= limits.first))
83+
return false;
84+
if ((node.second < 0) || (node.second >= limits.second))
85+
return false;
86+
return true;
87+
}
88+
89+
auto solve_part_1(const std::pair<Antenna, std::pair<int, int>> &instructions) -> int {
90+
auto antinodes = std::unordered_set<std::pair<int, int>>{};
91+
auto antenna_map = instructions.first;
92+
93+
for (auto &[v1, antennas] : antenna_map) {
94+
auto combinations = Itertools::combinations(antennas, 2);
95+
auto offsets = std::vector<std::pair<int, int>>{};
96+
offsets.reserve(combinations.size());
97+
std::ranges::transform(combinations, std::back_inserter(offsets), [](const auto &vec) -> std::pair<int, int> {
98+
auto v1 = vec.front();
99+
auto v2 = vec.back();
100+
return {v1.first - v2.first, v1.second - v2.second};
101+
});
102+
for (auto [offset, pair] : std::ranges::zip_view(offsets, combinations)) {
103+
auto node = std::pair<int, int>{};
104+
node = {pair.front().first + offset.first, pair.front().second + offset.second};
105+
if (in_bound(node, instructions.second))
106+
antinodes.insert(node);
107+
node = {pair.back().first - offset.first, pair.back().second - offset.second};
108+
if (in_bound(node, instructions.second))
109+
antinodes.insert(node);
110+
}
111+
}
112+
113+
return int(antinodes.size());
114+
}
115+
116+
auto solve_part_2(const std::pair<Antenna, std::pair<int, int>> &instructions) -> int {
117+
auto antinodes = std::unordered_set<std::pair<int, int>>{};
118+
auto antenna_map = instructions.first;
119+
120+
for (auto &[v1, antennas] : antenna_map) {
121+
auto combinations = Itertools::combinations(antennas, 2);
122+
for (auto &pair : combinations) {
123+
antinodes.insert(pair.front());
124+
antinodes.insert(pair.back());
125+
auto offset = std::pair<int, int>{pair.front().first - pair.back().first, pair.front().second - pair.back().second};
126+
auto node = std::pair<int, int>{};
127+
node = {pair.front().first + offset.first, pair.front().second + offset.second};
128+
while (in_bound(node, instructions.second)) {
129+
antinodes.insert(node);
130+
node.first += offset.first;
131+
node.second += offset.second;
132+
}
133+
node = {pair.back().first - offset.first, pair.back().second - offset.second};
134+
while (in_bound(node, instructions.second)) {
135+
antinodes.insert(node);
136+
node.first -= offset.first;
137+
node.second -= offset.second;
138+
}
139+
}
140+
}
141+
142+
return int(antinodes.size());
143+
}
144+
145+
void solve_all(const std::vector<std::string> &instructions) {
146+
auto parsed_instructions = aoc::timer(parse_instructions, instructions, "Preparation time:");
147+
aoc::timer(1, solve_part_1, parsed_instructions);
148+
aoc::timer(2, solve_part_2, parsed_instructions);
149+
}
150+
151+
auto main(int argc, char **argv) -> int {
152+
std::string filename;
153+
constexpr int year = 2024;
154+
constexpr int day = 8;
155+
156+
auto args = std::span(argv, argc);
157+
if (argc > 1) {
158+
if (std::string(args[1]) == "--test") {
159+
filename = "test_input.txt";
160+
} else {
161+
filename = args[1];
162+
}
163+
} else {
164+
filename = "input.txt";
165+
}
166+
167+
auto instructions = aoc::io::get_input_list<std::string>(filename, year, day);
168+
169+
aoc::io::header(year, day);
170+
aoc::timer(solve_all, instructions);
171+
172+
return 0;
173+
}

C++/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ While I try to learn the benefits and caveats of C++ I also decided to take on t
1313
| 5 | &#11088;&#11088; | | |
1414
| 6 | &#11088;&#11088; | | |
1515
| 7 | &#11088;&#11088; | | |
16+
| 8 | &#11088;&#11088; | | |
1617

1718
## 2023:
1819
| Day | Stars | Timing Part 1 | Timing Part 2 | Comment

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Solutions for [Advent of Code](https://adventofcode.com) in different languages.
55
## Year 2024
66
+ 22 &#11088; in [Python](python/README.md)
77
+ 17 &#11088; in [C](C/README.md)
8-
+ 12 &#11088; in [C++](C++/README.md)
8+
+ 14 &#11088; in [C++](C++/README.md)
99
+ 1 &#11088; in [Rust](Rust/README.md)
1010

1111
## Year 2023

0 commit comments

Comments
 (0)