Compare commits
6 Commits
676006891d
...
3223948f51
Author | SHA1 | Date |
---|---|---|
Benjamin Kraft | 3223948f51 | 9 months ago |
Benjamin Kraft | 2508d4cd51 | 9 months ago |
Benjamin Kraft | df538935a5 | 9 months ago |
Benjamin Kraft | 14ff577615 | 9 months ago |
Benjamin Kraft | ee36ea57db | 9 months ago |
Benjamin Kraft | 3f65baeccb | 9 months ago |
11 changed files with 485 additions and 30 deletions
@ -1,9 +1,79 @@ |
|||||||
#include "Day01.h" |
#include "Day01.h" |
||||||
|
|
||||||
Result Day01::Task1() { |
Result Day01::Task1() { |
||||||
return Day::Task1(); |
uint32_t sum = 0; |
||||||
|
for (const string& line : input){ |
||||||
|
uint8_t left = *std::find_if(line.begin(), line.end(), [](const char c){ |
||||||
|
int diff = c - '0'; |
||||||
|
return diff >= 0 && diff < 10; |
||||||
|
}) - '0'; |
||||||
|
uint8_t right = *std::find_if(std::make_reverse_iterator(line.end()), std::make_reverse_iterator(line.begin()), [](const char c){ |
||||||
|
int diff = c - '0'; |
||||||
|
return diff >= 0 && diff < 10; |
||||||
|
}) - '0'; |
||||||
|
sum += left * 10 + right; |
||||||
|
} |
||||||
|
return to_string(sum); |
||||||
} |
} |
||||||
|
|
||||||
Result Day01::Task2() { |
Result Day01::Task2() { |
||||||
return Day::Task2(); |
uint32_t sum = 0; |
||||||
|
|
||||||
|
std::map<string, char> convert = { |
||||||
|
{"one", '1'}, |
||||||
|
{"two", '2'}, |
||||||
|
{"three", '3'}, |
||||||
|
{"four", '4'}, |
||||||
|
{"five", '5'}, |
||||||
|
{"six", '6'}, |
||||||
|
{"seven", '7'}, |
||||||
|
{"eight", '8'}, |
||||||
|
{"nine", '9'}, |
||||||
|
}; |
||||||
|
|
||||||
|
for (const string &line : input){ |
||||||
|
|
||||||
|
uint8_t left = 0, right = 0; |
||||||
|
for (size_t i = 0; i < line.length(); i++){ |
||||||
|
auto current = line.substr(0, i + 1); |
||||||
|
auto diff = current.back() - '0'; |
||||||
|
if (diff > 0 && diff < 10){ |
||||||
|
left = diff; |
||||||
|
break; |
||||||
|
} |
||||||
|
bool found = false; |
||||||
|
for (const auto& [key, value] : convert){ |
||||||
|
auto pos = current.find(key); |
||||||
|
if (pos != string::npos){ |
||||||
|
left = value - '0'; |
||||||
|
found = true; |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
if (found) break; |
||||||
|
} |
||||||
|
|
||||||
|
for (size_t i = 0; i < line.length(); i++){ |
||||||
|
auto current = line.substr(line.length() - i - 1); |
||||||
|
auto diff = current.front() - '0'; |
||||||
|
if (diff > 0 && diff < 10){ |
||||||
|
right = diff; |
||||||
|
break; |
||||||
|
} |
||||||
|
bool found = false; |
||||||
|
for (const auto& [key, value] : convert){ |
||||||
|
auto pos = current.find(key); |
||||||
|
if (pos != string::npos){ |
||||||
|
right = value - '0'; |
||||||
|
found = true; |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
if (found) break; |
||||||
|
} |
||||||
|
|
||||||
|
sum += left * 10 + right; |
||||||
|
} |
||||||
|
|
||||||
|
return to_string(sum); |
||||||
} |
} |
@ -1,9 +1,65 @@ |
|||||||
#include "Day02.h" |
#include "Day02.h" |
||||||
|
|
||||||
Result Day02::Task1() { |
Result Day02::Task1() { |
||||||
return Day::Task1(); |
int r = 12; |
||||||
|
int g = 13; |
||||||
|
int b = 14; |
||||||
|
|
||||||
|
uint32_t sum = 0; |
||||||
|
uint32_t id = 1; |
||||||
|
for (const Game &game : parseGames()){ |
||||||
|
bool possible = true; |
||||||
|
for (const auto &set : game) |
||||||
|
if (set[0] > r || set[1] > g || set[2] > b) |
||||||
|
possible = false; |
||||||
|
if (possible) |
||||||
|
sum += id; |
||||||
|
|
||||||
|
id++; |
||||||
|
} |
||||||
|
return to_string(sum); |
||||||
} |
} |
||||||
|
|
||||||
Result Day02::Task2() { |
Result Day02::Task2() { |
||||||
return Day::Task2(); |
uint32_t sum = 0; |
||||||
} |
for (const Game &game : parseGames()){ |
||||||
|
size_t r = 0, g = 0, b = 0; |
||||||
|
for (const auto &set : game){ |
||||||
|
r = std::max(r, set[0]); |
||||||
|
g = std::max(g, set[1]); |
||||||
|
b = std::max(b, set[2]); |
||||||
|
} |
||||||
|
sum += r * g * b; |
||||||
|
} |
||||||
|
return to_string(sum); |
||||||
|
} |
||||||
|
|
||||||
|
vector<Day02::Game> Day02::parseGames() const { |
||||||
|
vector<Game> games; |
||||||
|
for (const string &line : input){ |
||||||
|
auto record = line.substr(line.find(": ") + 1); |
||||||
|
record.push_back(';'); |
||||||
|
auto setIndices = findAll(record, ";"); |
||||||
|
|
||||||
|
Game game; |
||||||
|
size_t start = 0; |
||||||
|
for (size_t i : setIndices){ |
||||||
|
auto set = record.substr(start, i - start); |
||||||
|
|
||||||
|
auto findNumber = [set](const string &type) -> size_t { |
||||||
|
auto pos = set.find(type); |
||||||
|
if (pos != string::npos) |
||||||
|
return std::stoul(set.substr(pos - 3, 2)); |
||||||
|
return 0; |
||||||
|
}; |
||||||
|
size_t r = findNumber("red"); |
||||||
|
size_t g = findNumber("green"); |
||||||
|
size_t b = findNumber("blue"); |
||||||
|
|
||||||
|
game.push_back({r, g, b}); |
||||||
|
start = i; |
||||||
|
} |
||||||
|
games.push_back(game); |
||||||
|
} |
||||||
|
return games; |
||||||
|
} |
||||||
|
@ -1,9 +1,102 @@ |
|||||||
#include "Day03.h" |
#include "Day03.h" |
||||||
|
|
||||||
Result Day03::Task1() { |
Result Day03::Task1() { |
||||||
return Day::Task1(); |
uint32_t sum = 0; |
||||||
|
|
||||||
|
auto isSymbol = [this](int32_t x, int32_t y) -> bool { |
||||||
|
if (x < 0 || x > input[0].length() - 1 || |
||||||
|
y < 0 || y > input.size() - 1){ |
||||||
|
return false; |
||||||
|
} |
||||||
|
char c = input[y][x]; |
||||||
|
return !isDigit(c) && c != '.'; |
||||||
|
}; |
||||||
|
|
||||||
|
for (const auto &[number, position] : parseEngineNumbers()){ |
||||||
|
auto &[value, size] = number; |
||||||
|
auto &[x, y] = position; |
||||||
|
|
||||||
|
bool symbolFound = false; |
||||||
|
for (int32_t sx = x - 1; sx < x + size + 1; sx++){ |
||||||
|
for (int32_t sy = y - 1; sy < y + 2; sy++){ |
||||||
|
if (isSymbol(sx, sy)){ |
||||||
|
symbolFound = true; |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
if (symbolFound) |
||||||
|
sum += value; |
||||||
|
} |
||||||
|
|
||||||
|
return to_string(sum); |
||||||
} |
} |
||||||
|
|
||||||
Result Day03::Task2() { |
Result Day03::Task2() { |
||||||
return Day::Task2(); |
uint32_t sum = 0; |
||||||
} |
|
||||||
|
map<pair<size_t, size_t>, set<EngineNumber>> stars; |
||||||
|
|
||||||
|
auto isStar = [this](int32_t x, int32_t y) -> bool { |
||||||
|
if (x < 0 || x > input[0].length() - 1 || |
||||||
|
y < 0 || y > input.size() - 1){ |
||||||
|
return false; |
||||||
|
} |
||||||
|
return input[y][x] == '*'; |
||||||
|
}; |
||||||
|
|
||||||
|
for (const auto &[number, position] : parseEngineNumbers()){ |
||||||
|
auto &[value, size] = number; |
||||||
|
auto &[x, y] = position; |
||||||
|
|
||||||
|
for (int32_t sx = x - 1; sx < x + size + 1; sx++){ |
||||||
|
for (int32_t sy = y - 1; sy < y + 2; sy++){ |
||||||
|
if (isStar(sx, sy)){ |
||||||
|
if (stars.contains({sx, sy})){ |
||||||
|
stars[{sx, sy}].insert({number, position}); |
||||||
|
} else { |
||||||
|
stars[{sx, sy}] = {{number, position}}; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
for (auto &[position, numbers] : stars){ |
||||||
|
if (numbers.size() == 2){ |
||||||
|
sum += numbers.begin()->first.first * (++numbers.begin())->first.first; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return to_string(sum); |
||||||
|
} |
||||||
|
|
||||||
|
vector<Day03::EngineNumber> Day03::parseEngineNumbers() const { |
||||||
|
vector<EngineNumber> numbers; |
||||||
|
|
||||||
|
for (size_t y = 0; y < input.size(); y++){ |
||||||
|
const string& line = input[y]; |
||||||
|
uint32_t value = 0; |
||||||
|
uint8_t valueLength = 0; |
||||||
|
bool readingValue = false; |
||||||
|
|
||||||
|
for (size_t x = 0; x < line.length(); x++){ |
||||||
|
uint8_t digit; |
||||||
|
if (isDigit(line[x], digit)){ |
||||||
|
value = value * 10 + digit; |
||||||
|
valueLength++; |
||||||
|
readingValue = true; |
||||||
|
if (x == line.length() - 1) |
||||||
|
numbers.push_back({{value, valueLength}, {x - valueLength, y}}); |
||||||
|
} else { |
||||||
|
if (readingValue) |
||||||
|
numbers.push_back({{value, valueLength}, {x - valueLength, y}}); |
||||||
|
readingValue = false; |
||||||
|
valueLength = 0; |
||||||
|
value = 0; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return numbers; |
||||||
|
} |
||||||
|
@ -1,9 +1,62 @@ |
|||||||
#include "Day04.h" |
#include "Day04.h" |
||||||
|
#include <cmath> |
||||||
|
|
||||||
Result Day04::Task1() { |
Result Day04::Task1() { |
||||||
return Day::Task1(); |
uint64 sum = 0; |
||||||
|
|
||||||
|
for (const auto &[winning, having] : parseCards()){ |
||||||
|
std::set<uint8_t> result; |
||||||
|
std::set_intersection(winning.begin(), winning.end(), having.begin(), having.end(), std::inserter(result, result.begin())); |
||||||
|
if (!result.empty()){ |
||||||
|
sum += uint64(powl(2, result.size() - 1)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return to_string(sum); |
||||||
} |
} |
||||||
|
|
||||||
Result Day04::Task2() { |
Result Day04::Task2() { |
||||||
return Day::Task2(); |
vector<uint64> matches; |
||||||
} |
|
||||||
|
for (const auto &[winning, having] : parseCards()){ |
||||||
|
std::set<uint8_t> result; |
||||||
|
std::set_intersection(winning.begin(), winning.end(), having.begin(), having.end(), std::inserter(result, result.begin())); |
||||||
|
matches.push_back(result.size()); |
||||||
|
} |
||||||
|
|
||||||
|
vector<uint64> counts(matches.size(), 1); |
||||||
|
|
||||||
|
for (size_t i = 0; i < matches.size(); i++){ |
||||||
|
for (size_t instance = 0; instance < counts[i]; instance++){ |
||||||
|
for (size_t k = 0; k < matches[i]; k++){ |
||||||
|
counts[i + k + 1]++; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
uint64 sum = std::reduce(counts.begin(), counts.end(), 0, [](uint64 a, uint64 b){return a + b;}); |
||||||
|
|
||||||
|
return to_string(sum); |
||||||
|
} |
||||||
|
|
||||||
|
vector<Day04::Card> Day04::parseCards() const { |
||||||
|
vector<Card> cards; |
||||||
|
|
||||||
|
for (string line : input){ |
||||||
|
line = line.substr(line.find(':') + 1); |
||||||
|
string left = line.substr(0, line.find(" |")); |
||||||
|
string right = line.substr(line.find(" |") + 2); |
||||||
|
|
||||||
|
set<uint8_t> winning; |
||||||
|
for (size_t i = 0; i < left.length(); i += 3) |
||||||
|
winning.insert(std::stoul(left.substr(i, 3))); |
||||||
|
|
||||||
|
set<uint8_t> having; |
||||||
|
for (size_t i = 0; i < right.length(); i += 3) |
||||||
|
having.insert(std::stoul(right.substr(i, 3))); |
||||||
|
|
||||||
|
cards.emplace_back(winning, having); |
||||||
|
} |
||||||
|
|
||||||
|
return cards; |
||||||
|
} |
||||||
|
@ -1,9 +1,125 @@ |
|||||||
#include "Day05.h" |
#include "Day05.h" |
||||||
|
|
||||||
Result Day05::Task1() { |
Result Day05::Task1() { |
||||||
return Day::Task1(); |
auto seeds = parseSeeds(); |
||||||
|
auto maps = parseMaps(); |
||||||
|
|
||||||
|
uint64 min = UINT64_MAX; |
||||||
|
|
||||||
|
for (uint64 seed : seeds){ |
||||||
|
uint64 result = seed; |
||||||
|
for (const Map &map : maps) |
||||||
|
result = map.get(result); |
||||||
|
min = std::min(min, result); |
||||||
|
} |
||||||
|
|
||||||
|
return to_string(min); |
||||||
} |
} |
||||||
|
|
||||||
Result Day05::Task2() { |
Result Day05::Task2() { |
||||||
return Day::Task2(); |
auto seeds = parseSeeds(); |
||||||
} |
auto maps = parseMaps(); |
||||||
|
|
||||||
|
uint64 min = UINT64_MAX; |
||||||
|
|
||||||
|
for (size_t i = 0; i < seeds.size(); i += 2){ |
||||||
|
vector<Range> resultRanges {Range(seeds[i], seeds[i] + seeds[i + 1] - 1)}; |
||||||
|
for (const Map &map : maps){ |
||||||
|
vector<Range> newRanges; |
||||||
|
for (const Range &range : resultRanges) { |
||||||
|
auto add = map.get(range); |
||||||
|
std::copy(add.begin(), add.end(), std::back_inserter(newRanges)); |
||||||
|
} |
||||||
|
resultRanges = newRanges; |
||||||
|
} |
||||||
|
for (const Range &range : resultRanges) |
||||||
|
min = std::min(min, range.start); |
||||||
|
} |
||||||
|
|
||||||
|
return to_string(min); |
||||||
|
} |
||||||
|
|
||||||
|
vector<uint64> Day05::parseSeeds() const { |
||||||
|
vector<uint64> seeds; |
||||||
|
auto list = (input[0] + " ").substr(7); |
||||||
|
size_t start = 0; |
||||||
|
for (size_t i : findAll(list, " ")){ |
||||||
|
seeds.push_back(std::stoul(list.substr(start, i - start))); |
||||||
|
start = i; |
||||||
|
} |
||||||
|
|
||||||
|
return seeds; |
||||||
|
} |
||||||
|
|
||||||
|
std::array<Day05::Map, 7> Day05::parseMaps() const { |
||||||
|
std::array<Map, 7> maps; |
||||||
|
|
||||||
|
size_t map = 0; |
||||||
|
|
||||||
|
for (size_t i = 3; i < input.size(); i++){ |
||||||
|
string line = input[i]; |
||||||
|
if (line.empty()){ |
||||||
|
i++; |
||||||
|
map++; |
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
vector<string> values = split(line, ' '); |
||||||
|
maps[map].mappings.insert(Mapping(std::stoul(values[0]), std::stoul(values[1]), std::stoul(values[2]))); |
||||||
|
} |
||||||
|
|
||||||
|
return maps; |
||||||
|
} |
||||||
|
|
||||||
|
uint64 Day05::Mapping::get(uint64 src) const { |
||||||
|
return src - source + destination; |
||||||
|
} |
||||||
|
|
||||||
|
Day05::Range Day05::Mapping::get(Day05::Range src) const { |
||||||
|
if (containsKey(src.start) && containsKey(src.end)) |
||||||
|
return Range(get(src.start), get(src.end)); |
||||||
|
if (containsKey(src.start)) |
||||||
|
return Range(get(src.start), get(source + range - 1)); |
||||||
|
if (containsKey(src.end)) |
||||||
|
return Range(get(source), get(src.end)); |
||||||
|
return Range(get(source), get(source + range - 1)); |
||||||
|
} |
||||||
|
|
||||||
|
bool Day05::Mapping::touchesRange(Day05::Range src) const { |
||||||
|
return !(src.end < source || src.start > source + range - 1); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
uint64 Day05::Map::get(uint64 src) const { |
||||||
|
for (const Mapping &mapping : mappings) |
||||||
|
if (mapping.containsKey(src)) |
||||||
|
return mapping.get(src); |
||||||
|
return src; |
||||||
|
} |
||||||
|
|
||||||
|
vector<Day05::Range> Day05::Map::get(Day05::Range src) const { |
||||||
|
vector<Range> ranges; |
||||||
|
|
||||||
|
uint64 minSource = mappings.begin()->source; |
||||||
|
uint64 maxSource = (--mappings.end())->source + (--mappings.end())->range - 1; |
||||||
|
if (src.end < minSource || src.start > maxSource) |
||||||
|
return {src}; |
||||||
|
if (src.start < minSource) |
||||||
|
ranges.emplace_back(src.start, minSource - 1); |
||||||
|
if (src.end > maxSource) |
||||||
|
ranges.emplace_back(maxSource + 1, src.end); |
||||||
|
|
||||||
|
for (const Mapping &mapping : mappings) |
||||||
|
if (mapping.touchesRange(src)) |
||||||
|
ranges.emplace_back(mapping.get(src)); |
||||||
|
|
||||||
|
return ranges; |
||||||
|
} |
||||||
|
|
||||||
|
bool Day05::Mapping::containsKey(uint64 src) const { |
||||||
|
return src >= source && src < source + range; |
||||||
|
} |
||||||
|
|
||||||
|
bool Day05::Mapping::operator<(const Day05::Mapping &other) const { |
||||||
|
return source < other.source; |
||||||
|
} |
||||||
|
@ -0,0 +1,47 @@ |
|||||||
|
#include "util.h" |
||||||
|
|
||||||
|
vector<size_t> findAll(const string& data, const string& toSearch){ |
||||||
|
vector<size_t> indices; |
||||||
|
|
||||||
|
size_t pos = data.find(toSearch); |
||||||
|
|
||||||
|
while (pos != string::npos){ |
||||||
|
indices.push_back(pos); |
||||||
|
|
||||||
|
pos = data.find(toSearch, pos + toSearch.size()); |
||||||
|
} |
||||||
|
|
||||||
|
return indices; |
||||||
|
} |
||||||
|
|
||||||
|
void removeAll(string& data, const string& toRemove) { |
||||||
|
vector<size_t> indices = findAll(data, toRemove); |
||||||
|
std::sort(indices.rbegin(), indices.rend()); |
||||||
|
for (size_t &i : indices) |
||||||
|
data.erase(i, toRemove.size()); |
||||||
|
} |
||||||
|
|
||||||
|
vector<string> split(const string& data, const char c){ |
||||||
|
vector<string> parts; |
||||||
|
size_t start = 0; |
||||||
|
for (size_t i : findAll(data, std::string(1, c))){ |
||||||
|
parts.push_back(data.substr(start, i - start)); |
||||||
|
start = i + 1; |
||||||
|
} |
||||||
|
parts.push_back(data.substr(start)); |
||||||
|
return parts; |
||||||
|
} |
||||||
|
|
||||||
|
bool isDigit(char c, uint8_t& result){ |
||||||
|
auto val = c - '0'; |
||||||
|
if (val >= 0 && val < 10){ |
||||||
|
result = val; |
||||||
|
return true; |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
bool isDigit(char c){ |
||||||
|
auto val = c - '0'; |
||||||
|
return val >= 0 && val < 10; |
||||||
|
} |
Loading…
Reference in new issue