diff options
Diffstat (limited to '2018')
| -rw-r--r-- | 2018/data/.gitkeep | 0 | ||||
| -rw-r--r-- | 2018/src/day01.cpp | 58 | ||||
| -rw-r--r-- | 2018/src/day02.cpp | 87 | ||||
| -rw-r--r-- | 2018/src/day03.cpp | 95 | ||||
| -rw-r--r-- | 2018/src/day04.cpp | 135 | ||||
| -rw-r--r-- | 2018/src/day05.cpp | 101 | ||||
| -rw-r--r-- | 2018/src/day06.cpp | 152 | ||||
| -rw-r--r-- | 2018/src/day07.cpp | 194 | ||||
| -rw-r--r-- | 2018/src/day08.cpp | 88 | ||||
| -rw-r--r-- | 2018/src/day09.cpp | 113 | ||||
| -rw-r--r-- | 2018/src/day10.cpp | 137 | ||||
| -rw-r--r-- | 2018/src/day11.cpp | 143 |
12 files changed, 1303 insertions, 0 deletions
diff --git a/2018/data/.gitkeep b/2018/data/.gitkeep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/2018/data/.gitkeep | |||
diff --git a/2018/src/day01.cpp b/2018/src/day01.cpp new file mode 100644 index 0000000..d57a187 --- /dev/null +++ b/2018/src/day01.cpp | |||
| @@ -0,0 +1,58 @@ | |||
| 1 | #include <filesystem> | ||
| 2 | #include <fstream> | ||
| 3 | #include <iostream> | ||
| 4 | #include <numeric> | ||
| 5 | #include <unordered_set> | ||
| 6 | #include <vector> | ||
| 7 | |||
| 8 | using namespace std; | ||
| 9 | |||
| 10 | namespace { | ||
| 11 | |||
| 12 | vector<long> | ||
| 13 | read_file(const filesystem::path& filename) | ||
| 14 | { | ||
| 15 | ifstream file{ filename }; | ||
| 16 | vector<long> values; | ||
| 17 | |||
| 18 | for ( long value = 0; file >> value; ) { | ||
| 19 | values.emplace_back(value); | ||
| 20 | } | ||
| 21 | |||
| 22 | return values; | ||
| 23 | } | ||
| 24 | |||
| 25 | void | ||
| 26 | part1(const vector<long>& values) | ||
| 27 | { | ||
| 28 | auto sum = accumulate(values.begin(), values.end(), 0L); | ||
| 29 | cout << "Part1: " << sum << '\n'; | ||
| 30 | } | ||
| 31 | |||
| 32 | void | ||
| 33 | part2(const vector<long>& values) | ||
| 34 | { | ||
| 35 | unordered_set<long> seen; | ||
| 36 | |||
| 37 | long sum = 0; | ||
| 38 | for ( size_t idx = 0;; ++idx ) { | ||
| 39 | sum += values.at(idx % values.size()); | ||
| 40 | |||
| 41 | if ( seen.contains(sum) ) { | ||
| 42 | cout << "Part2: " << sum << '\n'; | ||
| 43 | return; | ||
| 44 | } | ||
| 45 | |||
| 46 | seen.emplace(sum); | ||
| 47 | } | ||
| 48 | } | ||
| 49 | |||
| 50 | } // namespace | ||
| 51 | |||
| 52 | int | ||
| 53 | main() | ||
| 54 | { | ||
| 55 | auto values = read_file("data/day01.txt"); | ||
| 56 | part1(values); | ||
| 57 | part2(values); | ||
| 58 | } | ||
diff --git a/2018/src/day02.cpp b/2018/src/day02.cpp new file mode 100644 index 0000000..5dc6c7f --- /dev/null +++ b/2018/src/day02.cpp | |||
| @@ -0,0 +1,87 @@ | |||
| 1 | #include <filesystem> | ||
| 2 | #include <fstream> | ||
| 3 | #include <iostream> | ||
| 4 | #include <map> | ||
| 5 | #include <set> | ||
| 6 | #include <string> | ||
| 7 | #include <vector> | ||
| 8 | |||
| 9 | using namespace std; | ||
| 10 | |||
| 11 | namespace { | ||
| 12 | |||
| 13 | vector<string> | ||
| 14 | read_lines(const filesystem::path& filename) | ||
| 15 | { | ||
| 16 | ifstream file{ filename }; | ||
| 17 | vector<string> lines; | ||
| 18 | |||
| 19 | for ( string line; getline(file, line); ) { | ||
| 20 | lines.emplace_back(line); | ||
| 21 | } | ||
| 22 | |||
| 23 | return lines; | ||
| 24 | } | ||
| 25 | |||
| 26 | void | ||
| 27 | part1(const vector<string>& lines) | ||
| 28 | { | ||
| 29 | int twos = 0; | ||
| 30 | int threes = 0; | ||
| 31 | for ( const auto& line: lines ) { | ||
| 32 | map<char, int> foo; | ||
| 33 | for ( const auto chr: line ) { | ||
| 34 | foo[chr]++; | ||
| 35 | } | ||
| 36 | |||
| 37 | set<int> counts; | ||
| 38 | for ( const auto& [chr, count]: foo ) { | ||
| 39 | counts.insert(count); | ||
| 40 | } | ||
| 41 | |||
| 42 | if ( counts.contains(2) ) { | ||
| 43 | ++twos; | ||
| 44 | } | ||
| 45 | if ( counts.contains(3) ) { | ||
| 46 | ++threes; | ||
| 47 | } | ||
| 48 | } | ||
| 49 | cout << "Part 1: " << twos * threes << '\n'; | ||
| 50 | } | ||
| 51 | |||
| 52 | void | ||
| 53 | part2(const vector<string>& lines) | ||
| 54 | { | ||
| 55 | for ( size_t i = 0; i != lines.size(); ++i ) { | ||
| 56 | for ( size_t j = i + 1; j != lines.size(); ++j ) { | ||
| 57 | const auto& lhs = lines.at(i); | ||
| 58 | const auto& rhs = lines.at(j); | ||
| 59 | |||
| 60 | if ( lhs.length() != rhs.length() ) { | ||
| 61 | throw runtime_error("invalid data"); | ||
| 62 | } | ||
| 63 | |||
| 64 | string result; | ||
| 65 | for ( size_t k = 0; k != lhs.length(); ++k ) { | ||
| 66 | if ( lhs[k] == rhs[k] ) { | ||
| 67 | result += lhs[k]; | ||
| 68 | } | ||
| 69 | } | ||
| 70 | |||
| 71 | if ( result.length() + 1 == lhs.length() ) { | ||
| 72 | cout << "Part 2: " << result << '\n'; | ||
| 73 | return; | ||
| 74 | } | ||
| 75 | } | ||
| 76 | } | ||
| 77 | } | ||
| 78 | |||
| 79 | } // namespace | ||
| 80 | |||
| 81 | int | ||
| 82 | main() | ||
| 83 | { | ||
| 84 | auto lines = read_lines("data/day02.txt"); | ||
| 85 | part1(lines); | ||
| 86 | part2(lines); | ||
| 87 | } | ||
diff --git a/2018/src/day03.cpp b/2018/src/day03.cpp new file mode 100644 index 0000000..bed3acb --- /dev/null +++ b/2018/src/day03.cpp | |||
| @@ -0,0 +1,95 @@ | |||
| 1 | #include <filesystem> | ||
| 2 | #include <fstream> | ||
| 3 | #include <iostream> | ||
| 4 | #include <map> | ||
| 5 | #include <regex> | ||
| 6 | #include <set> | ||
| 7 | #include <tuple> | ||
| 8 | #include <vector> | ||
| 9 | |||
| 10 | using namespace std; | ||
| 11 | |||
| 12 | namespace { | ||
| 13 | |||
| 14 | struct Claim { | ||
| 15 | int id; | ||
| 16 | int left; | ||
| 17 | int top; | ||
| 18 | int width; | ||
| 19 | int height; | ||
| 20 | }; | ||
| 21 | |||
| 22 | #if 0 | ||
| 23 | ostream& | ||
| 24 | operator<<(ostream& ostrm, const Claim& claim) | ||
| 25 | { | ||
| 26 | ostrm << "id: " << claim.id | ||
| 27 | << " (" << claim.left << ", " << claim.top << ": " << claim.width << "x" << claim.height; | ||
| 28 | return ostrm; | ||
| 29 | } | ||
| 30 | #endif | ||
| 31 | |||
| 32 | vector<Claim> | ||
| 33 | read_file(const filesystem::path& filename) | ||
| 34 | { | ||
| 35 | ifstream file{ filename }; | ||
| 36 | vector<Claim> claims; | ||
| 37 | |||
| 38 | regex pattern(R"#((\d+) @ (\d+),(\d+): (\d+)x(\d+))#"); | ||
| 39 | smatch match; | ||
| 40 | |||
| 41 | for ( string line; getline(file, line); ) { | ||
| 42 | if ( !regex_search(line, match, pattern) ) { | ||
| 43 | continue; | ||
| 44 | } | ||
| 45 | |||
| 46 | Claim claim{}; | ||
| 47 | claim.id = stoi(match[1]); | ||
| 48 | claim.left = stoi(match[2]); | ||
| 49 | claim.top = stoi(match[3]); | ||
| 50 | claim.width = stoi(match[4]); | ||
| 51 | claim.height = stoi(match[5]); | ||
| 52 | |||
| 53 | claims.emplace_back(claim); | ||
| 54 | } | ||
| 55 | |||
| 56 | return claims; | ||
| 57 | } | ||
| 58 | |||
| 59 | void | ||
| 60 | solve(const vector<Claim>& claims) | ||
| 61 | { | ||
| 62 | map<tuple<int, int>, vector<int>> fabric; | ||
| 63 | set<int> allIds; | ||
| 64 | |||
| 65 | for ( const auto& claim: claims ) { | ||
| 66 | for ( int x = claim.left; x < claim.left + claim.width; ++x ) { | ||
| 67 | for ( int y = claim.top; y < claim.top + claim.height; ++y ) { | ||
| 68 | fabric[{ x, y }].emplace_back(claim.id); | ||
| 69 | } | ||
| 70 | } | ||
| 71 | allIds.emplace(claim.id); | ||
| 72 | } | ||
| 73 | |||
| 74 | int overlapCount = 0; | ||
| 75 | for ( const auto& [pos, ids]: fabric ) { | ||
| 76 | if ( ids.size() > 1 ) { | ||
| 77 | ++overlapCount; | ||
| 78 | for ( const auto& id: ids ) { | ||
| 79 | allIds.erase(id); | ||
| 80 | } | ||
| 81 | } | ||
| 82 | } | ||
| 83 | |||
| 84 | cout << "Part 1: " << overlapCount << '\n'; | ||
| 85 | cout << "Part 2: " << *allIds.begin() << '\n'; | ||
| 86 | } | ||
| 87 | |||
| 88 | } // namespace | ||
| 89 | |||
| 90 | int | ||
| 91 | main() | ||
| 92 | { | ||
| 93 | auto claims = read_file("data/day03.txt"); | ||
| 94 | solve(claims); | ||
| 95 | } | ||
diff --git a/2018/src/day04.cpp b/2018/src/day04.cpp new file mode 100644 index 0000000..ea3c69f --- /dev/null +++ b/2018/src/day04.cpp | |||
| @@ -0,0 +1,135 @@ | |||
| 1 | #include <algorithm> | ||
| 2 | #include <filesystem> | ||
| 3 | #include <fstream> | ||
| 4 | #include <iostream> | ||
| 5 | #include <map> | ||
| 6 | #include <string> | ||
| 7 | #include <vector> | ||
| 8 | |||
| 9 | using namespace std; | ||
| 10 | |||
| 11 | namespace { | ||
| 12 | |||
| 13 | struct Record { | ||
| 14 | int guard_id; | ||
| 15 | long start_sleep; | ||
| 16 | long stop_sleep; | ||
| 17 | }; | ||
| 18 | |||
| 19 | long | ||
| 20 | to_timestamp(const string& line) | ||
| 21 | { | ||
| 22 | long year = stol(line.substr(1, 4)); | ||
| 23 | long mon = stol(line.substr(6, 2)); | ||
| 24 | long day = stol(line.substr(9, 2)); | ||
| 25 | long hour = stol(line.substr(12, 2)); | ||
| 26 | long min = stol(line.substr(15, 2)); | ||
| 27 | |||
| 28 | auto timestamp = (year * 100'000'000) + (mon * 1'000'000) + (day * 10'000) + (hour * 100) + min; // NOLINT | ||
| 29 | |||
| 30 | return timestamp; | ||
| 31 | } | ||
| 32 | |||
| 33 | vector<Record> | ||
| 34 | read_file(const filesystem::path& filename) | ||
| 35 | { | ||
| 36 | ifstream file{ filename }; | ||
| 37 | vector<string> lines; | ||
| 38 | |||
| 39 | for ( string line; getline(file, line); ) { | ||
| 40 | lines.emplace_back(line); | ||
| 41 | } | ||
| 42 | |||
| 43 | ranges::sort(lines); | ||
| 44 | |||
| 45 | vector<Record> records; | ||
| 46 | |||
| 47 | int guard = -1; | ||
| 48 | long start_sleep = -1; | ||
| 49 | long stop_sleep = -1; | ||
| 50 | for ( const auto& line: lines ) { | ||
| 51 | if ( line.find(" Guard #") != string::npos ) { | ||
| 52 | guard = stoi(line.substr(26)); | ||
| 53 | } | ||
| 54 | else if ( line.find(" falls asleep") != string::npos ) { | ||
| 55 | start_sleep = to_timestamp(line); | ||
| 56 | } | ||
| 57 | else if ( line.find(" wakes up") != string::npos ) { | ||
| 58 | stop_sleep = to_timestamp(line); | ||
| 59 | records.emplace_back(guard, start_sleep, stop_sleep); | ||
| 60 | } | ||
| 61 | } | ||
| 62 | |||
| 63 | return records; | ||
| 64 | } | ||
| 65 | |||
| 66 | void | ||
| 67 | part1(const vector<Record>& records) | ||
| 68 | { | ||
| 69 | map<int, long> sleep_amounts; | ||
| 70 | |||
| 71 | for ( const auto& record: records ) { | ||
| 72 | sleep_amounts[record.guard_id] += record.stop_sleep - record.start_sleep; | ||
| 73 | } | ||
| 74 | |||
| 75 | auto max_amount = ranges::max_element(sleep_amounts, | ||
| 76 | [](const auto& lhs, const auto& rhs) { | ||
| 77 | return lhs.second < rhs.second; | ||
| 78 | }); | ||
| 79 | |||
| 80 | map<long, unsigned> sleep_counts; | ||
| 81 | |||
| 82 | for ( const auto& record: records ) { | ||
| 83 | if ( record.guard_id != max_amount->first ) { | ||
| 84 | continue; | ||
| 85 | } | ||
| 86 | |||
| 87 | for ( auto timestamp = record.start_sleep; timestamp != record.stop_sleep; ++timestamp ) { | ||
| 88 | sleep_counts[timestamp % 10'000]++; | ||
| 89 | } | ||
| 90 | } | ||
| 91 | |||
| 92 | auto max_count = ranges::max_element(sleep_counts, | ||
| 93 | [](const auto& lhs, const auto& rhs) { | ||
| 94 | return lhs.second < rhs.second; | ||
| 95 | }); | ||
| 96 | |||
| 97 | cout << "Part 1: " << max_amount->first * (max_count->first % 100) << '\n'; | ||
| 98 | } | ||
| 99 | |||
| 100 | void | ||
| 101 | part2(const vector<Record>& records) | ||
| 102 | { | ||
| 103 | map<int, map<long, unsigned>> sleep_counts; | ||
| 104 | |||
| 105 | for ( const auto& record: records ) { | ||
| 106 | for ( auto timestamp = record.start_sleep; timestamp != record.stop_sleep; ++timestamp ) { | ||
| 107 | sleep_counts[record.guard_id][timestamp % 10'000]++; | ||
| 108 | } | ||
| 109 | } | ||
| 110 | |||
| 111 | int found_guard = -1; | ||
| 112 | long found_min = -1; | ||
| 113 | unsigned max_count = 0; | ||
| 114 | for ( const auto& [id, times]: sleep_counts ) { | ||
| 115 | for ( const auto& [min, count]: times ) { | ||
| 116 | if ( count > max_count ) { | ||
| 117 | max_count = count; | ||
| 118 | found_guard = id; | ||
| 119 | found_min = min % 100; | ||
| 120 | } | ||
| 121 | } | ||
| 122 | } | ||
| 123 | |||
| 124 | cout << "Part 2: " << found_guard * found_min << '\n'; | ||
| 125 | } | ||
| 126 | |||
| 127 | } // namespace | ||
| 128 | |||
| 129 | int | ||
| 130 | main() | ||
| 131 | { | ||
| 132 | auto records = read_file("data/day04.txt"); | ||
| 133 | part1(records); | ||
| 134 | part2(records); | ||
| 135 | } | ||
diff --git a/2018/src/day05.cpp b/2018/src/day05.cpp new file mode 100644 index 0000000..9de484d --- /dev/null +++ b/2018/src/day05.cpp | |||
| @@ -0,0 +1,101 @@ | |||
| 1 | #include <filesystem> | ||
| 2 | #include <fstream> | ||
| 3 | #include <iostream> | ||
| 4 | #include <string> | ||
| 5 | |||
| 6 | using namespace std; | ||
| 7 | |||
| 8 | namespace { | ||
| 9 | |||
| 10 | string | ||
| 11 | read_line(const filesystem::path& filename) | ||
| 12 | { | ||
| 13 | ifstream file{ filename }; | ||
| 14 | string line; | ||
| 15 | getline(file, line); | ||
| 16 | return line; | ||
| 17 | } | ||
| 18 | |||
| 19 | bool | ||
| 20 | xorEqual(char lhs, char rhs) | ||
| 21 | { | ||
| 22 | return (lhs ^ (1 << 5)) == rhs; | ||
| 23 | } | ||
| 24 | |||
| 25 | #if 0 | ||
| 26 | void | ||
| 27 | part1(string str) | ||
| 28 | { | ||
| 29 | size_t idx = 1; | ||
| 30 | while ( idx < str.length() ) { | ||
| 31 | if ( xorEqual(str[idx - 1], str[idx]) ) { | ||
| 32 | str.erase(idx - 1, 2); | ||
| 33 | idx = 1; | ||
| 34 | } | ||
| 35 | else { | ||
| 36 | ++idx; | ||
| 37 | } | ||
| 38 | } | ||
| 39 | |||
| 40 | cout << "Part 1: " << str.length() << '\n'; | ||
| 41 | } | ||
| 42 | #endif | ||
| 43 | |||
| 44 | void | ||
| 45 | part1_opti(string_view str) | ||
| 46 | { | ||
| 47 | string result; | ||
| 48 | |||
| 49 | for ( const auto chr: str ) { | ||
| 50 | if ( !result.empty() && xorEqual(result.back(), chr) ) { | ||
| 51 | result.pop_back(); | ||
| 52 | } | ||
| 53 | else { | ||
| 54 | result.push_back(chr); | ||
| 55 | } | ||
| 56 | } | ||
| 57 | |||
| 58 | cout << "Part 1: " << result.length() << '\n'; | ||
| 59 | } | ||
| 60 | |||
| 61 | void | ||
| 62 | part2(string_view str) | ||
| 63 | { | ||
| 64 | size_t min_length = str.size(); | ||
| 65 | for ( auto ch = 'a'; ch != 'z'; ++ch ) { | ||
| 66 | string result; | ||
| 67 | |||
| 68 | for ( const auto chr: str ) { | ||
| 69 | if ( tolower(chr) == ch ) { | ||
| 70 | // nichts | ||
| 71 | } | ||
| 72 | else if ( !result.empty() && xorEqual(result.back(), chr) ) { | ||
| 73 | result.pop_back(); | ||
| 74 | } | ||
| 75 | else { | ||
| 76 | result.push_back(chr); | ||
| 77 | } | ||
| 78 | } | ||
| 79 | min_length = min(min_length, result.length()); | ||
| 80 | } | ||
| 81 | |||
| 82 | cout << "Part 2: " << min_length << '\n'; | ||
| 83 | } | ||
| 84 | |||
| 85 | } // namespace | ||
| 86 | |||
| 87 | int | ||
| 88 | main() | ||
| 89 | { | ||
| 90 | auto line = read_line("data/day05.txt"); | ||
| 91 | // part1(line); | ||
| 92 | part1_opti(line); | ||
| 93 | part2(line); | ||
| 94 | /* | ||
| 95 | cout << reduce("aA") << '\n'; | ||
| 96 | cout << reduce("abBA") << '\n'; | ||
| 97 | cout << reduce("abAB") << '\n'; | ||
| 98 | cout << reduce("aabAAB") << '\n'; | ||
| 99 | cout << reduce("dabAcCaCBAcCcaDA") << '\n'; | ||
| 100 | */ | ||
| 101 | } | ||
diff --git a/2018/src/day06.cpp b/2018/src/day06.cpp new file mode 100644 index 0000000..8701cbe --- /dev/null +++ b/2018/src/day06.cpp | |||
| @@ -0,0 +1,152 @@ | |||
| 1 | #include <filesystem> | ||
| 2 | #include <fstream> | ||
| 3 | #include <iostream> | ||
| 4 | #include <map> | ||
| 5 | #include <set> | ||
| 6 | #include <tuple> | ||
| 7 | |||
| 8 | using namespace std; | ||
| 9 | |||
| 10 | namespace { | ||
| 11 | |||
| 12 | using Point = tuple<int, int>; | ||
| 13 | |||
| 14 | set<Point> | ||
| 15 | read_file(const filesystem::path& filename) | ||
| 16 | { | ||
| 17 | ifstream file{ filename }; | ||
| 18 | set<Point> points; | ||
| 19 | |||
| 20 | int x{}; | ||
| 21 | int y{}; | ||
| 22 | char sep{}; | ||
| 23 | |||
| 24 | while ( file >> x >> sep >> y ) { | ||
| 25 | points.insert({ x, y }); | ||
| 26 | } | ||
| 27 | |||
| 28 | return points; | ||
| 29 | } | ||
| 30 | |||
| 31 | void | ||
| 32 | getBoundingBox(const set<Point>& points, Point& topLeft, Point& bottomRight) | ||
| 33 | { | ||
| 34 | auto minX = numeric_limits<int>::max(); | ||
| 35 | auto minY = numeric_limits<int>::max(); | ||
| 36 | auto maxX = numeric_limits<int>::min(); | ||
| 37 | auto maxY = numeric_limits<int>::min(); | ||
| 38 | |||
| 39 | for ( const auto [x, y]: points ) { | ||
| 40 | minX = min(minX, x); | ||
| 41 | minY = min(minY, y); | ||
| 42 | maxX = max(maxX, x); | ||
| 43 | maxY = max(maxY, y); | ||
| 44 | } | ||
| 45 | |||
| 46 | topLeft = { minX, minY }; | ||
| 47 | bottomRight = { maxX, maxY }; | ||
| 48 | } | ||
| 49 | |||
| 50 | int | ||
| 51 | manhattanDistance(const Point& lhs, const Point& rhs) | ||
| 52 | { | ||
| 53 | int distance = abs(get<0>(lhs) - get<0>(rhs)) + abs(get<1>(lhs) - get<1>(rhs)); | ||
| 54 | |||
| 55 | return distance; | ||
| 56 | } | ||
| 57 | |||
| 58 | void | ||
| 59 | part1(const set<Point>& points) | ||
| 60 | { | ||
| 61 | Point topLeft{}; | ||
| 62 | Point bottomRight{}; | ||
| 63 | getBoundingBox(points, topLeft, bottomRight); | ||
| 64 | |||
| 65 | const auto [minX, minY] = topLeft; | ||
| 66 | const auto [maxX, maxY] = bottomRight; | ||
| 67 | |||
| 68 | map<Point, int> areaCount; | ||
| 69 | set<Point> infinite; | ||
| 70 | |||
| 71 | static const int offset = 1; | ||
| 72 | |||
| 73 | for ( auto posX = minX - offset; posX <= maxX + offset; ++posX ) { | ||
| 74 | for ( auto posY = minY - offset; posY <= maxY + offset; ++posY ) { | ||
| 75 | int bestDistance = numeric_limits<int>::max(); | ||
| 76 | Point bestPoint{}; | ||
| 77 | bool tie = false; | ||
| 78 | |||
| 79 | for ( const auto& point: points ) { | ||
| 80 | int distance = manhattanDistance(point, { posX, posY }); | ||
| 81 | if ( distance < bestDistance ) { | ||
| 82 | bestDistance = distance; | ||
| 83 | bestPoint = point; | ||
| 84 | tie = false; | ||
| 85 | } | ||
| 86 | else if ( distance == bestDistance ) { | ||
| 87 | tie = true; | ||
| 88 | } | ||
| 89 | } | ||
| 90 | |||
| 91 | if ( !tie ) { | ||
| 92 | areaCount[bestPoint]++; | ||
| 93 | |||
| 94 | if ( posX < minX || posX > maxX || posY < minY || posY > maxY ) { | ||
| 95 | infinite.insert(bestPoint); | ||
| 96 | } | ||
| 97 | } | ||
| 98 | } | ||
| 99 | } | ||
| 100 | |||
| 101 | int maxSize = 0; | ||
| 102 | for ( const auto& [point, size]: areaCount ) { | ||
| 103 | if ( infinite.contains(point) ) { | ||
| 104 | continue; | ||
| 105 | } | ||
| 106 | maxSize = max(maxSize, size); | ||
| 107 | } | ||
| 108 | |||
| 109 | cout << "Part 1: " << maxSize << '\n'; | ||
| 110 | } | ||
| 111 | |||
| 112 | void | ||
| 113 | part2(const set<Point>& points, const int threshold) | ||
| 114 | { | ||
| 115 | Point topLeft{}; | ||
| 116 | Point bottomRight{}; | ||
| 117 | getBoundingBox(points, topLeft, bottomRight); | ||
| 118 | |||
| 119 | const auto [minX, minY] = topLeft; | ||
| 120 | const auto [maxX, maxY] = bottomRight; | ||
| 121 | |||
| 122 | static const int offset = 100; | ||
| 123 | |||
| 124 | unsigned int regionSize = 0; | ||
| 125 | |||
| 126 | for ( auto posX = minX - offset; posX <= maxX + offset; ++posX ) { | ||
| 127 | for ( auto posY = minY - offset; posY <= maxY + offset; ++posY ) { | ||
| 128 | int sum = 0; | ||
| 129 | |||
| 130 | for ( const auto& point: points ) { | ||
| 131 | int distance = manhattanDistance(point, { posX, posY }); | ||
| 132 | sum += distance; | ||
| 133 | } | ||
| 134 | |||
| 135 | if ( sum < threshold ) { | ||
| 136 | ++regionSize; | ||
| 137 | } | ||
| 138 | } | ||
| 139 | } | ||
| 140 | |||
| 141 | cout << "Part 2: " << regionSize << '\n'; | ||
| 142 | } | ||
| 143 | |||
| 144 | } // namespace | ||
| 145 | |||
| 146 | int | ||
| 147 | main() | ||
| 148 | { | ||
| 149 | auto points = read_file("data/day06.txt"); | ||
| 150 | part1(points); | ||
| 151 | part2(points, 10000); | ||
| 152 | } | ||
diff --git a/2018/src/day07.cpp b/2018/src/day07.cpp new file mode 100644 index 0000000..e6147d6 --- /dev/null +++ b/2018/src/day07.cpp | |||
| @@ -0,0 +1,194 @@ | |||
| 1 | #include <filesystem> | ||
| 2 | #include <fstream> | ||
| 3 | #include <iostream> | ||
| 4 | #include <map> | ||
| 5 | #include <set> | ||
| 6 | #include <sstream> | ||
| 7 | #include <string> | ||
| 8 | #include <vector> | ||
| 9 | |||
| 10 | using namespace std; | ||
| 11 | |||
| 12 | namespace { | ||
| 13 | |||
| 14 | vector<string> | ||
| 15 | split(const string& line) | ||
| 16 | { | ||
| 17 | stringstream strm{ line }; | ||
| 18 | vector<string> words; | ||
| 19 | |||
| 20 | for ( string word; getline(strm, word, ' '); ) { | ||
| 21 | words.emplace_back(word); | ||
| 22 | } | ||
| 23 | |||
| 24 | return words; | ||
| 25 | } | ||
| 26 | |||
| 27 | map<string, set<string>> | ||
| 28 | read_file(const filesystem::path& filename) | ||
| 29 | { | ||
| 30 | ifstream file{ filename }; | ||
| 31 | map<string, set<string>> graph; | ||
| 32 | |||
| 33 | for ( string line; getline(file, line); ) { | ||
| 34 | auto words = split(line); | ||
| 35 | graph[words.at(1)].emplace(words.at(7)); | ||
| 36 | } | ||
| 37 | |||
| 38 | return graph; | ||
| 39 | } | ||
| 40 | |||
| 41 | vector<string> | ||
| 42 | topologicalSort(const map<string, set<string>>& graph) | ||
| 43 | { | ||
| 44 | map<string, int> indegree; | ||
| 45 | |||
| 46 | // Eingangsgrade initialisieren | ||
| 47 | for ( const auto& [node, neighbors]: graph ) { | ||
| 48 | if ( !indegree.contains(node) ) { | ||
| 49 | indegree[node] = 0; | ||
| 50 | } | ||
| 51 | for ( const auto& neighbor: neighbors ) { | ||
| 52 | indegree[neighbor]++; | ||
| 53 | } | ||
| 54 | } | ||
| 55 | |||
| 56 | // Queue mit Knoten, deren Eingangsgrad 0 ist | ||
| 57 | priority_queue<string, vector<string>, greater<>> queue; | ||
| 58 | for ( const auto& [node, deg]: indegree ) { | ||
| 59 | if ( deg == 0 ) { | ||
| 60 | queue.push(node); | ||
| 61 | } | ||
| 62 | } | ||
| 63 | |||
| 64 | vector<string> sorted; | ||
| 65 | |||
| 66 | // Kahn's Algorithmus | ||
| 67 | while ( !queue.empty() ) { | ||
| 68 | string node = queue.top(); | ||
| 69 | queue.pop(); | ||
| 70 | |||
| 71 | sorted.push_back(node); | ||
| 72 | |||
| 73 | if ( !graph.contains(node) ) { | ||
| 74 | continue; | ||
| 75 | } | ||
| 76 | |||
| 77 | for ( const auto& neighbor: graph.at(node) ) { | ||
| 78 | indegree[neighbor]--; | ||
| 79 | if ( indegree[neighbor] == 0 ) { | ||
| 80 | queue.push(neighbor); | ||
| 81 | } | ||
| 82 | } | ||
| 83 | } | ||
| 84 | |||
| 85 | // Prüfen auf Zyklus | ||
| 86 | if ( sorted.size() != indegree.size() ) { | ||
| 87 | throw runtime_error("Zyklus im Graph gefunden! Keine topologische Sortierung möglich."); | ||
| 88 | } | ||
| 89 | |||
| 90 | return sorted; | ||
| 91 | } | ||
| 92 | |||
| 93 | void | ||
| 94 | part1(const map<string, set<string>>& graph) | ||
| 95 | { | ||
| 96 | auto sorted = topologicalSort(graph); | ||
| 97 | |||
| 98 | cout << "Part 1: "; | ||
| 99 | ranges::copy(sorted, ostream_iterator<string>(cout)); | ||
| 100 | cout << '\n'; | ||
| 101 | } | ||
| 102 | |||
| 103 | void | ||
| 104 | part2(const map<string, set<string>>& graph, const int workers, const int base) | ||
| 105 | { | ||
| 106 | map<string, int> indegree; | ||
| 107 | |||
| 108 | // Eingangsgrade initialisieren | ||
| 109 | for ( const auto& [node, neighbors]: graph ) { | ||
| 110 | if ( !indegree.contains(node) ) { | ||
| 111 | indegree[node] = 0; | ||
| 112 | } | ||
| 113 | for ( const auto& neighbor: neighbors ) { | ||
| 114 | indegree[neighbor]++; | ||
| 115 | } | ||
| 116 | } | ||
| 117 | |||
| 118 | set<string> available; | ||
| 119 | for ( const auto& [node, deg]: indegree ) { | ||
| 120 | if ( deg == 0 ) { | ||
| 121 | available.insert(node); | ||
| 122 | } | ||
| 123 | } | ||
| 124 | |||
| 125 | set<pair<int, string>> finishing; | ||
| 126 | |||
| 127 | int active_workers = 0; | ||
| 128 | int time = 0; | ||
| 129 | |||
| 130 | while ( !indegree.empty() ) { | ||
| 131 | while ( !finishing.empty() && finishing.begin()->first == time ) { | ||
| 132 | auto [finish_time, node] = *finishing.begin(); | ||
| 133 | finishing.erase(finishing.begin()); | ||
| 134 | |||
| 135 | active_workers--; | ||
| 136 | |||
| 137 | indegree.erase(node); | ||
| 138 | |||
| 139 | if ( !graph.contains(node) ) { | ||
| 140 | continue; | ||
| 141 | } | ||
| 142 | |||
| 143 | for ( const auto& neighbor: graph.at(node) ) { | ||
| 144 | indegree[neighbor]--; | ||
| 145 | if ( indegree[neighbor] == 0 ) { | ||
| 146 | available.insert(neighbor); | ||
| 147 | } | ||
| 148 | } | ||
| 149 | } | ||
| 150 | |||
| 151 | while ( active_workers < workers && !available.empty() ) { | ||
| 152 | auto node = *available.begin(); | ||
| 153 | available.erase(available.begin()); | ||
| 154 | |||
| 155 | int duration = base + (node.at(0) - 'A' + 1); | ||
| 156 | int finish_time = time + duration; | ||
| 157 | |||
| 158 | finishing.emplace(finish_time, node); | ||
| 159 | active_workers++; | ||
| 160 | } | ||
| 161 | |||
| 162 | if ( finishing.empty() ) { | ||
| 163 | if ( available.empty() ) { | ||
| 164 | break; | ||
| 165 | } | ||
| 166 | else { | ||
| 167 | time++; | ||
| 168 | } | ||
| 169 | } | ||
| 170 | else { | ||
| 171 | time = finishing.begin()->first; | ||
| 172 | } | ||
| 173 | } | ||
| 174 | |||
| 175 | cout << "Part 2: " << time << '\n'; | ||
| 176 | } | ||
| 177 | |||
| 178 | } // namespace | ||
| 179 | |||
| 180 | int | ||
| 181 | main() | ||
| 182 | { | ||
| 183 | auto graph = read_file("data/day07.txt"); | ||
| 184 | try { | ||
| 185 | part1(graph); | ||
| 186 | |||
| 187 | static const int WORKERS = 5; | ||
| 188 | static const int BASE = 60; | ||
| 189 | part2(graph, WORKERS, BASE); | ||
| 190 | } | ||
| 191 | catch ( exception& e ) { | ||
| 192 | cerr << "Fehler: " << e.what() << '\n'; | ||
| 193 | } | ||
| 194 | } | ||
diff --git a/2018/src/day08.cpp b/2018/src/day08.cpp new file mode 100644 index 0000000..9c2a093 --- /dev/null +++ b/2018/src/day08.cpp | |||
| @@ -0,0 +1,88 @@ | |||
| 1 | #include <filesystem> | ||
| 2 | #include <fstream> | ||
| 3 | #include <iostream> | ||
| 4 | #include <vector> | ||
| 5 | |||
| 6 | using namespace std; | ||
| 7 | |||
| 8 | namespace { | ||
| 9 | |||
| 10 | vector<int> | ||
| 11 | read_file(const filesystem::path& filename) | ||
| 12 | { | ||
| 13 | ifstream file{ filename }; | ||
| 14 | vector<int> data; | ||
| 15 | |||
| 16 | for ( int number{}; file >> number; ) { | ||
| 17 | data.emplace_back(number); | ||
| 18 | } | ||
| 19 | |||
| 20 | return data; | ||
| 21 | } | ||
| 22 | |||
| 23 | void | ||
| 24 | part1(const vector<int>& data) | ||
| 25 | { | ||
| 26 | size_t idx = 0; | ||
| 27 | int sum = 0; | ||
| 28 | |||
| 29 | function<void()> func = [&] { | ||
| 30 | auto count_child = data.at(idx++); | ||
| 31 | auto count_meta = data.at(idx++); | ||
| 32 | |||
| 33 | while ( count_child-- > 0 ) { | ||
| 34 | func(); | ||
| 35 | } | ||
| 36 | |||
| 37 | while ( count_meta-- > 0 ) { | ||
| 38 | sum += data.at(idx++); | ||
| 39 | } | ||
| 40 | }; | ||
| 41 | |||
| 42 | func(); | ||
| 43 | |||
| 44 | cout << "Part 1: " << sum << '\n'; | ||
| 45 | } | ||
| 46 | |||
| 47 | void | ||
| 48 | part2(const vector<int>& data) | ||
| 49 | { | ||
| 50 | size_t idx = 0; | ||
| 51 | |||
| 52 | function<int()> func = [&] { | ||
| 53 | const auto count_child = data.at(idx++); | ||
| 54 | const auto count_meta = data.at(idx++); | ||
| 55 | |||
| 56 | vector<int> child_values; | ||
| 57 | for ( int i = 0; i != count_child; ++i ) { | ||
| 58 | child_values.emplace_back(func()); | ||
| 59 | } | ||
| 60 | |||
| 61 | int value = 0; | ||
| 62 | for ( int i = 0; i != count_meta; ++i ) { | ||
| 63 | auto meta = data.at(idx++); | ||
| 64 | if ( count_child == 0 ) { | ||
| 65 | value += meta; | ||
| 66 | } | ||
| 67 | else { | ||
| 68 | meta--; | ||
| 69 | if ( meta >= 0 && meta < count_child ) { | ||
| 70 | value += child_values[static_cast<size_t>(meta)]; | ||
| 71 | } | ||
| 72 | } | ||
| 73 | } | ||
| 74 | return value; | ||
| 75 | }; | ||
| 76 | |||
| 77 | cout << "Part 2: " << func() << '\n'; | ||
| 78 | } | ||
| 79 | |||
| 80 | } // namespace | ||
| 81 | |||
| 82 | int | ||
| 83 | main() | ||
| 84 | { | ||
| 85 | auto data = read_file("data/day08.txt"); | ||
| 86 | part1(data); | ||
| 87 | part2(data); | ||
| 88 | } | ||
diff --git a/2018/src/day09.cpp b/2018/src/day09.cpp new file mode 100644 index 0000000..d1b4eb0 --- /dev/null +++ b/2018/src/day09.cpp | |||
| @@ -0,0 +1,113 @@ | |||
| 1 | #include <iostream> | ||
| 2 | #include <vector> | ||
| 3 | |||
| 4 | using namespace std; | ||
| 5 | |||
| 6 | namespace { | ||
| 7 | |||
| 8 | struct Marble { | ||
| 9 | explicit Marble(long score) | ||
| 10 | : score{ score } | ||
| 11 | { | ||
| 12 | } | ||
| 13 | |||
| 14 | Marble(long score, Marble* prev, Marble* next) | ||
| 15 | : score{ score } | ||
| 16 | , prev{ prev } | ||
| 17 | , next{ next } | ||
| 18 | { | ||
| 19 | } | ||
| 20 | |||
| 21 | [[nodiscard]] | ||
| 22 | Marble* insert_after_two(long value) const | ||
| 23 | { | ||
| 24 | auto* insert_after = this->next; | ||
| 25 | |||
| 26 | auto* new_marble = new Marble(value, insert_after, insert_after->next); // NOLINT | ||
| 27 | |||
| 28 | insert_after->next->prev = new_marble; | ||
| 29 | insert_after->next = new_marble; | ||
| 30 | |||
| 31 | return new_marble; | ||
| 32 | } | ||
| 33 | |||
| 34 | [[nodiscard]] | ||
| 35 | pair<Marble*, long> remove_seventh_back() | ||
| 36 | { | ||
| 37 | auto* to_remove = this; | ||
| 38 | for ( int i = 0; i != 7; ++i ) { | ||
| 39 | to_remove = to_remove->prev; | ||
| 40 | } | ||
| 41 | |||
| 42 | to_remove->prev->next = to_remove->next; | ||
| 43 | to_remove->next->prev = to_remove->prev; | ||
| 44 | |||
| 45 | auto* new_current = to_remove->next; | ||
| 46 | auto score = to_remove->score; | ||
| 47 | |||
| 48 | delete to_remove; // NOLINT | ||
| 49 | |||
| 50 | return { new_current, score }; | ||
| 51 | } | ||
| 52 | |||
| 53 | long score; | ||
| 54 | Marble* prev{ this }; | ||
| 55 | Marble* next{ this }; | ||
| 56 | }; | ||
| 57 | |||
| 58 | long | ||
| 59 | solve(const size_t players, const long last_marble) | ||
| 60 | { | ||
| 61 | auto current = new Marble(0); // NOLINT | ||
| 62 | |||
| 63 | vector<long> scores(players, 0); | ||
| 64 | size_t player = 0; | ||
| 65 | |||
| 66 | for ( long marble = 1; marble <= last_marble; ++marble ) { | ||
| 67 | if ( marble % 23 != 0 ) { | ||
| 68 | current = current->insert_after_two(marble); | ||
| 69 | } | ||
| 70 | else { | ||
| 71 | auto [new_current, removed_score] = current->remove_seventh_back(); | ||
| 72 | |||
| 73 | scores[player] += marble + removed_score; | ||
| 74 | current = new_current; | ||
| 75 | } | ||
| 76 | |||
| 77 | player += 1; | ||
| 78 | player %= players; | ||
| 79 | } | ||
| 80 | |||
| 81 | Marble* start = current; | ||
| 82 | do { | ||
| 83 | Marble* next = start->next; | ||
| 84 | delete start; // NOLINT | ||
| 85 | start = next; | ||
| 86 | } while ( start != current ); | ||
| 87 | |||
| 88 | return ranges::max(scores); | ||
| 89 | } | ||
| 90 | |||
| 91 | void | ||
| 92 | part1(const size_t players, const long last_marble) | ||
| 93 | { | ||
| 94 | cout << "Part 1: " << solve(players, last_marble) << '\n'; | ||
| 95 | } | ||
| 96 | |||
| 97 | void | ||
| 98 | part2(const size_t players, const long last_marble) | ||
| 99 | { | ||
| 100 | cout << "Part 2: " << solve(players, last_marble * 100) << '\n'; | ||
| 101 | } | ||
| 102 | |||
| 103 | } // namespace | ||
| 104 | |||
| 105 | int | ||
| 106 | main() | ||
| 107 | { | ||
| 108 | static const size_t players = 400; | ||
| 109 | static const long points = 71864; | ||
| 110 | |||
| 111 | part1(players, points); | ||
| 112 | part2(players, points); | ||
| 113 | } | ||
diff --git a/2018/src/day10.cpp b/2018/src/day10.cpp new file mode 100644 index 0000000..43de95c --- /dev/null +++ b/2018/src/day10.cpp | |||
| @@ -0,0 +1,137 @@ | |||
| 1 | #include <filesystem> | ||
| 2 | #include <fstream> | ||
| 3 | #include <iostream> | ||
| 4 | #include <regex> | ||
| 5 | #include <set> | ||
| 6 | #include <tuple> | ||
| 7 | #include <vector> | ||
| 8 | |||
| 9 | using namespace std; | ||
| 10 | |||
| 11 | namespace { | ||
| 12 | |||
| 13 | struct Point { | ||
| 14 | long x; | ||
| 15 | long y; | ||
| 16 | long vx; | ||
| 17 | long vy; | ||
| 18 | }; | ||
| 19 | |||
| 20 | vector<Point> | ||
| 21 | read_file(const filesystem::path& filename) | ||
| 22 | { | ||
| 23 | ifstream file{ filename }; | ||
| 24 | |||
| 25 | static const regex pattern{ R"(position=<\s*(-?\d+)\s*,\s*(-?\d+)\s*>\s*velocity=<\s*(-?\d+)\s*,\s*(-?\d+)\s*>)" }; | ||
| 26 | |||
| 27 | vector<Point> data; | ||
| 28 | for ( string line; getline(file, line); ) { | ||
| 29 | smatch match; | ||
| 30 | if ( regex_match(line, match, pattern) ) { | ||
| 31 | auto x = stol(match[1]); | ||
| 32 | auto y = stol(match[2]); | ||
| 33 | auto vx = stol(match[3]); | ||
| 34 | auto vy = stol(match[4]); | ||
| 35 | |||
| 36 | data.emplace_back(x, y, vx, vy); | ||
| 37 | } | ||
| 38 | } | ||
| 39 | |||
| 40 | return data; | ||
| 41 | } | ||
| 42 | |||
| 43 | void | ||
| 44 | get_bounding_box(const vector<Point>& points, long& min_x, long& min_y, long& max_x, long& max_y) | ||
| 45 | { | ||
| 46 | min_x = numeric_limits<long>::max(); | ||
| 47 | min_y = numeric_limits<long>::max(); | ||
| 48 | max_x = numeric_limits<long>::min(); | ||
| 49 | max_y = numeric_limits<long>::min(); | ||
| 50 | |||
| 51 | for ( const auto& point: points ) { | ||
| 52 | min_x = min(min_x, point.x); | ||
| 53 | min_y = min(min_y, point.y); | ||
| 54 | max_x = max(max_x, point.x); | ||
| 55 | max_y = max(max_y, point.y); | ||
| 56 | } | ||
| 57 | } | ||
| 58 | |||
| 59 | long | ||
| 60 | bounding_area(const vector<Point>& points) | ||
| 61 | { | ||
| 62 | long min_x = 0; | ||
| 63 | long min_y = 0; | ||
| 64 | long max_x = 0; | ||
| 65 | long max_y = 0; | ||
| 66 | get_bounding_box(points, min_x, min_y, max_x, max_y); | ||
| 67 | return 1L * (max_x - min_x + 1) * (max_y - min_y + 1); | ||
| 68 | } | ||
| 69 | |||
| 70 | void | ||
| 71 | update(vector<Point>& points) | ||
| 72 | { | ||
| 73 | for ( auto& point: points ) { | ||
| 74 | point.x += point.vx; | ||
| 75 | point.y += point.vy; | ||
| 76 | } | ||
| 77 | } | ||
| 78 | |||
| 79 | tuple<int, vector<Point>> | ||
| 80 | get_best(vector<Point> points) | ||
| 81 | { | ||
| 82 | auto best_area = numeric_limits<long>::max(); | ||
| 83 | |||
| 84 | vector<Point> best; | ||
| 85 | int best_t = 0; | ||
| 86 | |||
| 87 | for ( int i = 0; i != 100'000; ++i ) { | ||
| 88 | update(points); | ||
| 89 | |||
| 90 | auto area = bounding_area(points); | ||
| 91 | if ( area < best_area ) { | ||
| 92 | best_area = area; | ||
| 93 | best = points; | ||
| 94 | best_t = i + 1; | ||
| 95 | } | ||
| 96 | } | ||
| 97 | return { best_t, best }; | ||
| 98 | } | ||
| 99 | |||
| 100 | void | ||
| 101 | print(const vector<Point>& points) | ||
| 102 | { | ||
| 103 | set<tuple<long, long>> grid; | ||
| 104 | for ( const auto [x, y, vx, vy]: points ) { | ||
| 105 | grid.emplace(x, y); | ||
| 106 | } | ||
| 107 | |||
| 108 | long min_x = 0; | ||
| 109 | long min_y = 0; | ||
| 110 | long max_x = 0; | ||
| 111 | long max_y = 0; | ||
| 112 | get_bounding_box(points, min_x, min_y, max_x, max_y); | ||
| 113 | |||
| 114 | for ( long y = min_y; y <= max_y; ++y ) { | ||
| 115 | for ( long x = min_x; x <= max_x; ++x ) { | ||
| 116 | cout << (grid.contains({ x, y }) ? '#' : ' '); | ||
| 117 | } | ||
| 118 | cout << '\n'; | ||
| 119 | } | ||
| 120 | } | ||
| 121 | |||
| 122 | void | ||
| 123 | solve(const vector<Point>& points) | ||
| 124 | { | ||
| 125 | auto [time, best_points] = get_best(points); | ||
| 126 | print(best_points); | ||
| 127 | cout << "Part 2: " << time << '\n'; | ||
| 128 | } | ||
| 129 | |||
| 130 | } // namespace | ||
| 131 | |||
| 132 | int | ||
| 133 | main() | ||
| 134 | { | ||
| 135 | auto data = read_file("data/day10.txt"); | ||
| 136 | solve(data); | ||
| 137 | } | ||
diff --git a/2018/src/day11.cpp b/2018/src/day11.cpp new file mode 100644 index 0000000..1f8f9e2 --- /dev/null +++ b/2018/src/day11.cpp | |||
| @@ -0,0 +1,143 @@ | |||
| 1 | #include <iostream> | ||
| 2 | #include <map> | ||
| 3 | |||
| 4 | using namespace std; | ||
| 5 | |||
| 6 | namespace { | ||
| 7 | |||
| 8 | const int WIDTH = 300; | ||
| 9 | const int HEIGHT = 300; | ||
| 10 | |||
| 11 | using Grid = map<tuple<int, int>, int>; | ||
| 12 | |||
| 13 | int | ||
| 14 | power_level(int x, int y, int serial) | ||
| 15 | { | ||
| 16 | auto rack_id = x + 10; | ||
| 17 | auto level = rack_id * y; | ||
| 18 | level += serial; | ||
| 19 | level *= rack_id; | ||
| 20 | level /= 100; | ||
| 21 | level %= 10; | ||
| 22 | level -= 5; | ||
| 23 | return level; | ||
| 24 | } | ||
| 25 | |||
| 26 | Grid | ||
| 27 | build_grid(int serial) | ||
| 28 | { | ||
| 29 | Grid grid; | ||
| 30 | for ( int x = 1; x <= WIDTH; ++x ) { | ||
| 31 | for ( int y = 1; y <= HEIGHT; ++y ) { | ||
| 32 | grid[{ x, y }] = power_level(x, y, serial); | ||
| 33 | } | ||
| 34 | } | ||
| 35 | return grid; | ||
| 36 | } | ||
| 37 | |||
| 38 | int | ||
| 39 | sum3x3(const Grid& grid, int x, int y) | ||
| 40 | { | ||
| 41 | auto sum = 0; | ||
| 42 | for ( int dx = 0; dx != 3; ++dx ) { | ||
| 43 | for ( int dy = 0; dy != 3; ++dy ) { | ||
| 44 | sum += grid.at({ x + dx, y + dy }); | ||
| 45 | } | ||
| 46 | } | ||
| 47 | return sum; | ||
| 48 | } | ||
| 49 | |||
| 50 | void | ||
| 51 | part1(const int serial) | ||
| 52 | { | ||
| 53 | auto grid = build_grid(serial); | ||
| 54 | |||
| 55 | auto best_sum = numeric_limits<int>::min(); | ||
| 56 | auto best_x = 0; | ||
| 57 | auto best_y = 0; | ||
| 58 | |||
| 59 | for ( int x = 1; x <= WIDTH - 2; ++x ) { | ||
| 60 | for ( int y = 1; y <= HEIGHT - 2; ++y ) { | ||
| 61 | if ( auto sum = sum3x3(grid, x, y); sum > best_sum ) { | ||
| 62 | best_sum = sum; | ||
| 63 | best_x = x; | ||
| 64 | best_y = y; | ||
| 65 | } | ||
| 66 | } | ||
| 67 | } | ||
| 68 | |||
| 69 | cout << "Part 1: " << best_x << ',' << best_y << '\n'; | ||
| 70 | } | ||
| 71 | |||
| 72 | Grid | ||
| 73 | pre_process(const Grid& grid) | ||
| 74 | { | ||
| 75 | Grid sat; | ||
| 76 | |||
| 77 | for ( int y = 1; y <= HEIGHT; ++y ) { | ||
| 78 | for ( int x = 1; x <= WIDTH; ++x ) { | ||
| 79 | const auto a = grid.at({ x, y }); | ||
| 80 | const auto b = (x > 1) ? sat.at({ x - 1, y }) : 0; | ||
| 81 | const auto c = (y > 1) ? sat.at({ x, y - 1 }) : 0; | ||
| 82 | const auto d = (x > 1 && y > 1) ? sat.at({ x - 1, y - 1 }) : 0; | ||
| 83 | |||
| 84 | sat[{ x, y }] = a + b + c - d; | ||
| 85 | } | ||
| 86 | } | ||
| 87 | |||
| 88 | return sat; | ||
| 89 | } | ||
| 90 | |||
| 91 | int | ||
| 92 | get_safe(const Grid& grid, int x, int y) | ||
| 93 | { | ||
| 94 | return (x < 1 || y < 1) ? 0 : grid.at({ x, y }); | ||
| 95 | } | ||
| 96 | |||
| 97 | int | ||
| 98 | square_sum(const Grid& grid, int x, int y, int s) | ||
| 99 | { | ||
| 100 | int x2 = x + s - 1; | ||
| 101 | int y2 = y + s - 1; | ||
| 102 | |||
| 103 | return get_safe(grid, x2, y2) - get_safe(grid, x - 1, y2) - get_safe(grid, x2, y - 1) + get_safe(grid, x - 1, y - 1); | ||
| 104 | } | ||
| 105 | |||
| 106 | void | ||
| 107 | part2(const int serial) | ||
| 108 | { | ||
| 109 | static const int MAX_SIZE = 100; | ||
| 110 | |||
| 111 | auto grid = pre_process(build_grid(serial)); | ||
| 112 | |||
| 113 | auto best_sum = numeric_limits<int>::min(); | ||
| 114 | auto best_x = 0; | ||
| 115 | auto best_y = 0; | ||
| 116 | auto best_s = 0; | ||
| 117 | |||
| 118 | for ( int s = 1; s <= MAX_SIZE; ++s ) { | ||
| 119 | for ( int x = 1; x <= WIDTH - s + 1; ++x ) { | ||
| 120 | for ( int y = 1; y <= HEIGHT - s + 1; ++y ) { | ||
| 121 | if ( auto sum = square_sum(grid, x, y, s); sum > best_sum ) { | ||
| 122 | best_sum = sum; | ||
| 123 | best_x = x; | ||
| 124 | best_y = y; | ||
| 125 | best_s = s; | ||
| 126 | } | ||
| 127 | } | ||
| 128 | } | ||
| 129 | } | ||
| 130 | |||
| 131 | cout << "Part 2: " << best_x << ',' << best_y << "," << best_s << '\n'; | ||
| 132 | } | ||
| 133 | |||
| 134 | } // namespace | ||
| 135 | |||
| 136 | int | ||
| 137 | main() | ||
| 138 | { | ||
| 139 | static const int SERIAL = 7989; | ||
| 140 | |||
| 141 | part1(SERIAL); | ||
| 142 | part2(SERIAL); | ||
| 143 | } | ||
