Compare commits

...

6 Commits

  1. 74
      src/days/01/Day01.cpp
  2. 60
      src/days/02/Day02.cpp
  3. 3
      src/days/02/Day02.h
  4. 97
      src/days/03/Day03.cpp
  5. 3
      src/days/03/Day03.h
  6. 57
      src/days/04/Day04.cpp
  7. 3
      src/days/04/Day04.h
  8. 120
      src/days/05/Day05.cpp
  9. 22
      src/days/05/Day05.h
  10. 47
      src/util.cpp
  11. 21
      src/util.h

@ -1,9 +1,79 @@
#include "Day01.h"
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() {
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"
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() {
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;
}

@ -3,8 +3,11 @@
#include "../../Day.h"
class Day02 : public Day {
typedef vector<std::array<size_t, 3>> Game;
protected:
Result Task1() override;
Result Task2() override;
vector<Game> parseGames() const;
};

@ -1,9 +1,102 @@
#include "Day03.h"
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() {
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;
}

@ -3,8 +3,11 @@
#include "../../Day.h"
class Day03 : public Day {
typedef pair<pair<uint32_t, uint8_t>, pair<int32_t, int32_t>> EngineNumber;
protected:
Result Task1() override;
Result Task2() override;
vector<EngineNumber> parseEngineNumbers() const;
};

@ -1,9 +1,62 @@
#include "Day04.h"
#include <cmath>
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() {
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;
}

@ -3,8 +3,11 @@
#include "../../Day.h"
class Day04 : public Day {
typedef pair<set<uint8_t>, set<uint8_t>> Card;
protected:
Result Task1() override;
Result Task2() override;
vector<Card> parseCards() const;
};

@ -1,9 +1,125 @@
#include "Day05.h"
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() {
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;
}

@ -3,8 +3,30 @@
#include "../../Day.h"
class Day05 : public Day {
struct Range {
uint64 start;
uint64 end;
};
struct Mapping {
uint64 destination;
uint64 source;
uint64 range;
bool containsKey(uint64 src) const;
uint64 get(uint64 src) const;
bool touchesRange(Range src) const;
Range get(Range src) const;
bool operator <(const Mapping &other) const;
};
struct Map {
set<Mapping> mappings;
uint64 get(uint64 src) const;
vector<Range> get(Range src) const;
};
protected:
Result Task1() override;
Result Task2() override;
vector<uint64> parseSeeds() const;
std::array<Map, 7> parseMaps() const;
};

@ -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;
}

@ -20,23 +20,12 @@ using std::string, std::vector, std::pair, std::map;
using std::list, std::set, std::unordered_set;
using std::priority_queue;
inline vector<size_t> findAll(const string& data, const string& toSearch){
vector<size_t> indices;
vector<size_t> findAll(const string& data, const string& toSearch);
size_t pos = data.find(toSearch);
void removeAll(string& data, const string& toRemove);
while (pos != string::npos){
indices.push_back(pos);
vector<string> split(const string& data, char c);
pos = data.find(toSearch, pos + toSearch.size());
}
bool isDigit(char c, uint8_t& result);
return indices;
}
inline 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());
}
bool isDigit(char c);
Loading…
Cancel
Save