aboutsummaryrefslogtreecommitdiff
path: root/2017
diff options
context:
space:
mode:
authorThomas Schmucker <ts@its1.de>2025-11-07 12:04:46 +0100
committerThomas Schmucker <ts@its1.de>2025-11-07 12:04:46 +0100
commitbdd35a7bee7f23c912d0c453abc263805d8d8ccf (patch)
treedcd06076d36124ea8fdd16ea19db79717dde074c /2017
parent756f22d58bb198b8f34589c112e1003614ccdcd6 (diff)
downloadadvent-of-code-bdd35a7bee7f23c912d0c453abc263805d8d8ccf.tar.gz
advent-of-code-bdd35a7bee7f23c912d0c453abc263805d8d8ccf.tar.bz2
advent-of-code-bdd35a7bee7f23c912d0c453abc263805d8d8ccf.zip
aoc 2017, days 21-25
Diffstat (limited to '2017')
-rw-r--r--2017/src/day21.cpp186
-rw-r--r--2017/src/day22.cpp158
-rw-r--r--2017/src/day23.cpp158
-rw-r--r--2017/src/day24.cpp102
-rw-r--r--2017/src/day25.cpp128
5 files changed, 732 insertions, 0 deletions
diff --git a/2017/src/day21.cpp b/2017/src/day21.cpp
new file mode 100644
index 0000000..64af5b6
--- /dev/null
+++ b/2017/src/day21.cpp
@@ -0,0 +1,186 @@
1#include <algorithm>
2#include <filesystem>
3#include <fstream>
4#include <iostream>
5#include <map>
6#include <string>
7#include <vector>
8
9using namespace std;
10
11namespace {
12
13vector<string>
14split(const string& line, const string& delimiters)
15{
16 vector<string> result;
17
18 size_t start = 0;
19 size_t end = 0;
20
21 while ( (end = line.find_first_of(delimiters, start)) != string::npos ) {
22 if ( end != start ) {
23 result.emplace_back(line.substr(start, end - start));
24 }
25
26 start = end + 1;
27 }
28
29 if ( start != line.size() ) {
30 result.emplace_back(line.substr(start));
31 }
32
33 return result;
34}
35
36vector<string>
37rotate90(const vector<string>& input)
38{
39 if ( input.empty() ) {
40 return {};
41 }
42
43 const auto rows = input.size();
44 const auto cols = input[0].size();
45
46 vector<string> rotated(cols, string(rows, ' '));
47
48 for ( size_t row = 0; row != rows; ++row ) {
49 for ( size_t col = 0; col != cols; ++col ) {
50 rotated[col][rows - 1 - row] = input[row][col];
51 }
52 }
53
54 return rotated;
55}
56
57vector<string>
58flip(const vector<string>& input)
59{
60 vector<string> result = input;
61
62 // oder: ranges::reverse(result);
63 for ( auto& row: result ) {
64 ranges::reverse(row);
65 }
66
67 return result;
68}
69
70vector<vector<string>>
71generate_variants(vector<string> pattern)
72{
73 vector<vector<string>> variants;
74
75 for ( int flip_count = 0; flip_count < 2; ++flip_count ) {
76 for ( int round = 0; round < 4; ++round ) {
77 variants.push_back(pattern);
78 pattern = rotate90(pattern);
79 }
80 pattern = flip(pattern);
81 }
82
83 return variants;
84}
85
86map<vector<string>, vector<string>>
87read_file(const filesystem::path& filename)
88{
89 ifstream file{ filename };
90 map<vector<string>, vector<string>> data;
91
92 for ( string line; getline(file, line); ) {
93 auto parts = split(line, " ");
94 auto lhs = split(parts.at(0), "/");
95 auto rhs = split(parts.at(2), "/");
96
97 for ( const auto& variant: generate_variants(lhs) ) {
98 data[variant] = rhs;
99 }
100 }
101
102 return data;
103}
104
105vector<string>
106enhance(const vector<string>& image, const map<vector<string>, vector<string>>& rules)
107{
108 const auto size = image.size();
109 const auto block_size = (size % 2 == 0) ? 2U : 3U;
110 const auto new_block_size = block_size + 1;
111 const auto blocks_per_row = size / block_size;
112 const auto new_size = blocks_per_row * new_block_size;
113
114 vector<string> new_image(new_size, string(new_size, '.'));
115
116 // Für jeden Block...
117 for ( size_t block_row = 0; block_row != blocks_per_row; ++block_row ) {
118 for ( size_t block_col = 0; block_col != blocks_per_row; ++block_col ) {
119 // ...Extrahiere den Block als vector<string>
120 vector<string> block;
121 block.reserve(block_size);
122 for ( size_t row = 0; row != block_size; ++row ) {
123 block.push_back(image[(block_row * block_size) + row].substr(block_col * block_size, block_size));
124 }
125
126 const auto& new_block = rules.at(block);
127
128 // Füge neuen Block ins Bild ein
129 for ( size_t row = 0; row != new_block_size; ++row ) {
130 for ( size_t col = 0; col != new_block_size; ++col ) {
131 new_image[(block_row * new_block_size) + row][(block_col * new_block_size) + col] = new_block[row][col];
132 }
133 }
134 }
135 }
136
137 return new_image;
138}
139
140int
141count(const vector<string>& image)
142{
143 int count = 0;
144 for ( const auto& row: image ) {
145 for ( char chr: row ) {
146 if ( chr == '#' ) {
147 ++count;
148 }
149 }
150 }
151 return count;
152}
153
154int
155solve(const map<vector<string>, vector<string>>& rules, size_t iterations)
156{
157 vector<string> image = { ".#.", "..#", "###" };
158
159 while ( iterations-- > 0 ) {
160 image = enhance(image, rules);
161 }
162
163 return count(image);
164}
165
166void
167part1(const map<vector<string>, vector<string>>& rules)
168{
169 cout << "Part1: " << solve(rules, 5) << '\n';
170}
171
172void
173part2(const map<vector<string>, vector<string>>& rules)
174{
175 cout << "Part2: " << solve(rules, 18) << '\n';
176}
177
178} // namespace
179
180int
181main()
182{
183 auto rules = read_file("data/day21.txt");
184 part1(rules);
185 part2(rules);
186}
diff --git a/2017/src/day22.cpp b/2017/src/day22.cpp
new file mode 100644
index 0000000..2567fb1
--- /dev/null
+++ b/2017/src/day22.cpp
@@ -0,0 +1,158 @@
1#include <filesystem>
2#include <fstream>
3#include <iostream>
4#include <map>
5#include <set>
6#include <string>
7#include <tuple>
8
9using namespace std;
10
11namespace {
12
13set<tuple<int, int>>
14read_file(const filesystem::path& filename)
15{
16 ifstream file{ filename };
17 set<tuple<int, int>> data;
18
19 int row = 0;
20 for ( string line; getline(file, line); ) {
21 int col = 0;
22
23 for ( char chr: line ) {
24 if ( chr == '#' ) {
25 data.emplace(col, row);
26 }
27 ++col;
28 }
29
30 ++row;
31 }
32
33 return data;
34}
35
36#if 0
37void
38print(const set<tuple<int, int>>& grid, tuple<int, int> pos)
39{
40 for ( int y = -5; y < 5; ++y ) {
41 for ( int x = -5; x < 5; ++x ) {
42 auto coord = make_tuple(x, y);
43
44 if ( pos == coord ) {
45 cout << '[';
46 }
47 else {
48 cout << ' ';
49 }
50
51 auto chr = grid.contains(coord) ? '#' : '.';
52 cout << chr;
53
54 if ( pos == coord ) {
55 cout << ']';
56 }
57 else {
58 cout << ' ';
59 }
60 }
61 cout << '\n';
62 }
63 cout << '\n';
64}
65#endif
66
67void
68part1(set<tuple<int, int>> grid, tuple<int, int> pos)
69{
70 const array<tuple<int, int>, 4> dirs{
71 make_tuple(-1, 0),
72 make_tuple(0, -1),
73 make_tuple(1, 0),
74 make_tuple(0, 1)
75 };
76 unsigned dir = 1; // up
77
78 int infections = 0;
79 for ( int i = 0; i != 10000; ++i ) {
80 if ( grid.contains(pos) ) {
81 dir = (dir + 1) % 4;
82 grid.erase(pos);
83 }
84 else {
85 dir = (dir + 3) % 4;
86 grid.insert(pos);
87 ++infections;
88 }
89
90 auto [dx, dy] = dirs.at(dir);
91 get<0>(pos) += dx;
92 get<1>(pos) += dy;
93 }
94 cout << "Part1: " << infections << '\n';
95}
96
97void
98part2(set<tuple<int, int>> grid, tuple<int, int> pos)
99{
100 const array<tuple<int, int>, 4> dirs{
101 make_tuple(-1, 0),
102 make_tuple(0, -1),
103 make_tuple(1, 0),
104 make_tuple(0, 1)
105 };
106 unsigned dir = 1; // up
107
108 static const int weak = 0;
109 static const int infected = 1;
110 static const int flagged = 2;
111
112 map<tuple<int, int>, int> grid_;
113 for ( const auto& value: grid ) {
114 grid_[value] = infected;
115 }
116
117 int infections = 0;
118 for ( int i = 0; i != 10000000; ++i ) {
119 if ( !grid_.contains(pos) ) {
120 grid_[pos] = weak;
121 dir = (dir + 3) % 4;
122 }
123 else {
124 switch ( grid_[pos] ) {
125 case weak:
126 grid_[pos] = infected;
127 ++infections;
128 break;
129 case infected:
130 grid_[pos] = flagged;
131 dir = (dir + 1) % 4;
132 break;
133 case flagged:
134 grid_.erase(pos);
135 dir = (dir + 2) % 4;
136 break;
137 default:
138 cerr << "Wrong state!!" << '\n';
139 return;
140 }
141 }
142
143 auto [dx, dy] = dirs.at(dir);
144 get<0>(pos) += dx;
145 get<1>(pos) += dy;
146 }
147 cout << "Part2: " << infections << '\n';
148}
149
150} // namespace
151
152int
153main()
154{
155 auto grid = read_file("data/day22.txt");
156 part1(grid, { 12, 12 });
157 part2(grid, { 12, 12 });
158}
diff --git a/2017/src/day23.cpp b/2017/src/day23.cpp
new file mode 100644
index 0000000..1f4b960
--- /dev/null
+++ b/2017/src/day23.cpp
@@ -0,0 +1,158 @@
1#include <charconv>
2#include <filesystem>
3#include <fstream>
4#include <iostream>
5#include <map>
6#include <sstream>
7#include <string>
8#include <vector>
9
10using namespace std;
11
12namespace {
13
14template<typename T>
15struct CPU {
16 [[nodiscard]]
17 T get(const string& ref)
18 {
19 T value{};
20 auto [ptr, ec] = from_chars(ref.data(), ref.data() + ref.size(), value);
21
22 if ( ec == errc() ) {
23 return value;
24 }
25
26 return memory[ref];
27 }
28
29 void set(const string& ref, T value)
30 {
31 memory[ref] = value;
32 }
33
34 void sub(const string& ref, T value)
35 {
36 memory[ref] -= value;
37 }
38
39 void mul(const string& ref, T value)
40 {
41 memory[ref] *= value;
42 }
43
44 T execute(const vector<vector<string>>& code)
45 {
46 int mul_executed = 0;
47
48 for ( size_t ip = 0; ip < code.size(); ++ip ) {
49 const auto& line = code.at(ip);
50 const auto& opcode = line.at(0);
51
52 if ( opcode == "set" ) {
53 set(line.at(1), get(line.at(2)));
54 }
55 else if ( opcode == "sub" ) {
56 sub(line.at(1), get(line.at(2)));
57 }
58 else if ( opcode == "mul" ) {
59 ++mul_executed;
60 mul(line.at(1), get(line.at(2)));
61 }
62 else if ( opcode == "jnz" ) {
63 auto value = get(line.at(1));
64 if ( value != 0 ) {
65 auto offset = get(line.at(2));
66 ip += static_cast<size_t>(offset - 1);
67 }
68 }
69 else {
70 cerr << "unknown opcode: " << opcode << '\n';
71 return -1;
72 }
73 }
74 return mul_executed;
75 }
76
77 map<string, T> memory;
78};
79
80vector<string>
81split(const string& line)
82{
83 stringstream strm{ line };
84 vector<string> data;
85
86 for ( string line; strm >> line; ) {
87 data.emplace_back(line);
88 }
89
90 return data;
91}
92
93vector<vector<string>>
94read_file(const filesystem::path& filename)
95{
96 ifstream file{ filename };
97 vector<vector<string>> data;
98
99 for ( string line; getline(file, line); ) {
100 const auto parts = split(line);
101 data.emplace_back(parts);
102 }
103
104 return data;
105}
106
107void
108part1(const vector<vector<string>>& code)
109{
110 CPU<long> cpu{};
111
112 cout << "Part1: " << cpu.execute(code) << '\n';
113}
114
115void
116part2(const vector<vector<string>>& code)
117{
118 CPU<long> cpu{};
119 cpu.memory["a"] = 1;
120
121 // execute only initialization code
122 cpu.execute({ code.begin(), code.begin() + 8 });
123
124 auto b_start = cpu.memory["b"];
125 auto c_end = cpu.memory["c"];
126
127 auto is_prime = [](long n) {
128 if ( n < 2 ) {
129 return false;
130 }
131 for ( long i = 2; i * i <= n; ++i ) {
132 if ( n % i == 0 ) {
133 return false;
134 }
135 }
136 return true;
137 };
138
139 const long step = 17;
140 long memory_h = 0;
141 for ( long b = b_start; b <= c_end; b += step ) {
142 if ( !is_prime(b) ) {
143 ++memory_h;
144 }
145 }
146
147 cout << "Part2: " << memory_h << '\n';
148}
149
150} // namespace
151
152int
153main()
154{
155 auto instr = read_file("data/day23.txt");
156 part1(instr);
157 part2(instr);
158}
diff --git a/2017/src/day24.cpp b/2017/src/day24.cpp
new file mode 100644
index 0000000..fa4148c
--- /dev/null
+++ b/2017/src/day24.cpp
@@ -0,0 +1,102 @@
1#include <filesystem>
2#include <fstream>
3#include <iostream>
4#include <set>
5#include <vector>
6
7using namespace std;
8
9namespace {
10
11vector<tuple<long, long>>
12read_file(const filesystem::path& filename)
13{
14 ifstream file{ filename };
15 vector<tuple<long, long>> data;
16
17 long lhs = 0;
18 long rhs = 0;
19 char sep = 0;
20
21 while ( file >> lhs >> sep >> rhs ) {
22 data.emplace_back(lhs, rhs);
23 }
24 return data;
25}
26
27long
28strongest(const vector<tuple<long, long>>& data, long current = 0, const set<size_t>& used = {})
29{
30 long best_strength = 0;
31
32 for ( size_t i = 0; i != data.size(); ++i ) {
33 if ( used.contains(i) ) {
34 continue;
35 }
36
37 auto [lhs, rhs] = data.at(i);
38 if ( lhs == current || rhs == current ) {
39 auto next_port = (lhs == current) ? rhs : lhs;
40 auto new_used{ used };
41 new_used.emplace(i);
42 auto strength = lhs + rhs + strongest(data, next_port, new_used);
43 best_strength = max(best_strength, strength);
44 }
45 }
46
47 return best_strength;
48}
49
50tuple<long, size_t>
51strongest_and_longest(const vector<tuple<long, long>>& data, long current = 0, const set<size_t>& used = {})
52{
53 long best_strength = 0;
54 size_t best_length = 0;
55
56 for ( size_t i = 0; i != data.size(); ++i ) {
57 if ( used.contains(i) ) {
58 continue;
59 }
60
61 auto [lhs, rhs] = data.at(i);
62 if ( lhs == current || rhs == current ) {
63 auto next_port = (lhs == current) ? rhs : lhs;
64 auto new_used{ used };
65 new_used.emplace(i);
66 auto [sub_strength, sub_length] = strongest_and_longest(data, next_port, new_used);
67
68 auto total_strength = sub_strength + lhs + rhs;
69 auto total_length = sub_length + 1;
70
71 if ( total_length > best_length || (total_length == best_length && total_strength > best_strength) ) {
72 best_strength = total_strength;
73 best_length = total_length;
74 }
75 }
76 }
77
78 return make_tuple(best_strength, best_length);
79}
80
81void
82part1(const vector<tuple<long, long>>& data)
83{
84 cout << "Part1: " << strongest(data) << '\n';
85}
86
87void
88part2(const vector<tuple<long, long>>& data)
89{
90 auto [strength, length] = strongest_and_longest(data);
91 cout << "Part2: " << strength << '\n';
92}
93
94} // namespace
95
96int
97main()
98{
99 auto data = read_file("data/day24.txt");
100 part1(data);
101 part2(data);
102}
diff --git a/2017/src/day25.cpp b/2017/src/day25.cpp
new file mode 100644
index 0000000..36b7dd0
--- /dev/null
+++ b/2017/src/day25.cpp
@@ -0,0 +1,128 @@
1#include <array>
2#include <filesystem>
3#include <fstream>
4#include <iostream>
5#include <iterator>
6#include <map>
7#include <string>
8#include <vector>
9
10using namespace std;
11
12namespace {
13
14vector<string>
15split(const string& line, const string& delimiter)
16{
17 vector<string> result;
18
19 size_t start = 0;
20 size_t end = 0;
21
22 while ( (end = line.find(delimiter, start)) != string::npos ) {
23 if ( end != start ) {
24 result.emplace_back(line.substr(start, end - start));
25 }
26
27 start = end + delimiter.length();
28 }
29
30 if ( start != line.size() ) {
31 result.emplace_back(line.substr(start));
32 }
33
34 return result;
35}
36
37vector<vector<vector<string>>>
38read_file(const filesystem::path& filename)
39{
40 ifstream file{ filename };
41 string content{ istreambuf_iterator<char>{ file }, {} };
42
43 vector<vector<vector<string>>> result;
44
45 auto blocks = split(content, "\n\n");
46 for ( const auto& block: blocks ) {
47 vector<vector<string>> data;
48
49 auto lines = split(block, "\n");
50 for ( auto line: lines ) {
51 line.pop_back();
52 auto words = split(line, " ");
53 data.emplace_back(words);
54 }
55
56 result.emplace_back(data);
57 }
58
59 return result;
60}
61
62using action_type = tuple<int, int, string>; // value (0, 1), direction (-1, 1), next_state)
63using condition_type = array<action_type, 2>; // [0] -> action, [1] -> action
64using rule_type = map<string, condition_type>; // "A" -> condition
65using puzzle_type = tuple<string, int, rule_type>; // (start_state, steps, rules)
66
67puzzle_type
68parse_input(const vector<vector<vector<string>>>& input)
69{
70 rule_type rules{};
71
72 for ( size_t idx = 1; idx < input.size(); ++idx ) {
73 const auto& block = input.at(idx);
74
75 condition_type condition{};
76
77 for ( size_t i = 0; i != 2; ++i ) {
78 const auto base = i * 4;
79
80 auto read_val = stoul(block.at(base + 1).back());
81 auto write_val = stoi(block.at(base + 2).back());
82 auto dir = block.at(base + 3).back() == "left" ? -1 : 1;
83 auto next_state = block.at(base + 4).back();
84
85 condition.at(read_val) = { write_val, dir, next_state };
86 }
87
88 rules[block.at(0).back()] = condition;
89 }
90
91 auto start_state = input[0][0][3];
92 auto steps = stoi(input[0][1][5]);
93
94 return puzzle_type{ start_state, steps, rules };
95}
96
97void
98part1(const puzzle_type& puzzle)
99{
100 auto [state, steps, rules] = puzzle;
101
102 map<int, int> tape;
103
104 int pos = 0;
105
106 while ( steps-- > 0 ) {
107 auto value = tape[pos];
108 const auto& [write, move, next_state] = rules.at(state).at(size_t(value));
109 state = next_state;
110 tape[pos] = write;
111 pos += move;
112 }
113
114 int sum = 0;
115 for ( const auto& [key, value]: tape ) {
116 sum += value;
117 }
118 cout << "Part1: " << sum << '\n';
119}
120
121} // namespace
122
123int
124main()
125{
126 auto input = read_file("data/day25.txt");
127 part1(parse_input(input));
128}