Initial commit with solutions from 2024
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
#include "common/aoc.h"
|
||||
|
||||
namespace day01
|
||||
{
|
||||
using InputType = std::pair<std::vector<int>, std::vector<int>>;
|
||||
REGISTER_DAY(2024, Day01, InputType, int);
|
||||
|
||||
REGISTER_TEST_EXAMPLE(2024, Day01, ExampleInput, 1, 11);
|
||||
REGISTER_TEST(2024, Day01, Input, 1, 1834060);
|
||||
REGISTER_TEST_EXAMPLE(2024, Day01, ExampleInput, 2, 31);
|
||||
REGISTER_TEST(2024, Day01, Input, 2, 21607792);
|
||||
|
||||
READ_INPUT(input)
|
||||
{
|
||||
std::vector<int> aVec, bVec;
|
||||
std::string str;
|
||||
while (std::getline(input, str))
|
||||
{
|
||||
std::stringstream ss{str};
|
||||
int a, b;
|
||||
ss >> a >> b;
|
||||
aVec.emplace_back(a);
|
||||
bVec.emplace_back(b);
|
||||
}
|
||||
return {aVec, bVec};
|
||||
}
|
||||
|
||||
OUTPUT1(input)
|
||||
{
|
||||
std::vector<int> copyA = input.first;
|
||||
std::vector<int> copyB = input.second;
|
||||
std::sort(copyA.begin(), copyA.end());
|
||||
std::sort(copyB.begin(), copyB.end());
|
||||
int sum = 0;
|
||||
for (int i = 0; i < input.first.size(); i++)
|
||||
{
|
||||
sum += std::abs(copyA[i] - copyB[i]);
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
OUTPUT2(input)
|
||||
{
|
||||
std::map<int, int> idCount;
|
||||
for (int i : input.second)
|
||||
{
|
||||
idCount[i]++;
|
||||
}
|
||||
|
||||
int sum = 0;
|
||||
for (int i : input.first)
|
||||
{
|
||||
sum += i * idCount[i];
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
#include "common/aoc.h"
|
||||
|
||||
namespace day02
|
||||
{
|
||||
REGISTER_DAY(2024, Day02, std::vector<std::vector<int>>, int);
|
||||
|
||||
REGISTER_TEST_EXAMPLE(2024, Day02, ExampleInput, 1, 2);
|
||||
REGISTER_TEST(2024, Day02, Input, 1, 549);
|
||||
REGISTER_TEST_EXAMPLE(2024, Day02, ExampleInput, 2, 4);
|
||||
REGISTER_TEST(2024, Day02, Input, 2, 589);
|
||||
|
||||
READ_INPUT(input)
|
||||
{
|
||||
std::vector<std::vector<int>> list;
|
||||
std::string str;
|
||||
while (std::getline(input, str))
|
||||
{
|
||||
std::stringstream ss{str};
|
||||
list.emplace_back(Input::ReadInts(ss, ' '));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
bool Validate(const std::vector<int>& vec)
|
||||
{
|
||||
bool lt = vec[0] < vec[1];
|
||||
for (int j = 1; j < vec.size(); j++)
|
||||
{
|
||||
int diff = std::abs(vec[j] - vec[j - 1]);
|
||||
if (vec[j - 1] < vec[j] != lt || diff < 1 || diff > 3)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ValidateWithout(const std::vector<int>& vec, int index)
|
||||
{
|
||||
std::vector<int> cpy = vec;
|
||||
if (index < vec.size())
|
||||
cpy.erase(cpy.begin() + index);
|
||||
return Validate(cpy);
|
||||
}
|
||||
|
||||
OUTPUT1(input)
|
||||
{
|
||||
int sum = 0;
|
||||
for (int i = 0; i < input.size(); i++)
|
||||
{
|
||||
if (Validate(input[i]))
|
||||
{
|
||||
sum++;
|
||||
}
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
OUTPUT2(input)
|
||||
{
|
||||
int sum = 0;
|
||||
for (int i = 0; i < input.size(); i++)
|
||||
{
|
||||
for (int j = 0; j < input[i].size() + 1; j++)
|
||||
{
|
||||
if (ValidateWithout(input[i], j))
|
||||
{
|
||||
sum++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
#include "common/aoc.h"
|
||||
|
||||
namespace day03
|
||||
{
|
||||
REGISTER_DAY(2024, Day03, std::string, int32_t);
|
||||
|
||||
REGISTER_TEST_EXAMPLE(2024, Day03, ExampleInput, 1, 161);
|
||||
REGISTER_TEST(2024, Day03, Input, 1, 178794710);
|
||||
REGISTER_TEST_EXAMPLE(2024, Day03, ExampleInput, 2, 48);
|
||||
REGISTER_TEST(2024, Day03, Input, 2, 76729637);
|
||||
|
||||
READ_INPUT(input)
|
||||
{
|
||||
return Input::Read(input);
|
||||
}
|
||||
|
||||
int32_t Mult(const std::string& str)
|
||||
{
|
||||
int i, j;
|
||||
std::stringstream ss{str};
|
||||
ss >> "mul(" >> i >> "," >> j >> ")";
|
||||
return i * j;
|
||||
}
|
||||
|
||||
OUTPUT1(input)
|
||||
{
|
||||
int32_t sum = 0;
|
||||
std::vector<std::string> matches = Helper::GetAllRegexMatches(input, "mul\\([0-9]*,[0-9]*\\)");
|
||||
for (auto& str : matches) sum += Mult(str);
|
||||
return sum;
|
||||
}
|
||||
|
||||
OUTPUT2(input)
|
||||
{
|
||||
int32_t sum = 0;
|
||||
bool mul = true;
|
||||
std::vector<std::string> matches =
|
||||
Helper::GetAllRegexMatches(input, "(mul\\([0-9]*,[0-9]*\\)|do\\(\\)|don\'t\\(\\))");
|
||||
for (auto& str : matches)
|
||||
{
|
||||
if (str == "do()")
|
||||
mul = true;
|
||||
else if (str == "don\'t()")
|
||||
mul = false;
|
||||
else if (mul)
|
||||
sum += Mult(str);
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
#include "common/aoc.h"
|
||||
|
||||
namespace day04
|
||||
{
|
||||
REGISTER_DAY(2024, Day04, Array2D<char>, int32_t);
|
||||
|
||||
REGISTER_TEST_EXAMPLE(2024, Day04, ExampleInput, 1, 18);
|
||||
REGISTER_TEST(2024, Day04, Input, 1, 2543);
|
||||
REGISTER_TEST_EXAMPLE(2024, Day04, ExampleInput, 2, 9);
|
||||
REGISTER_TEST(2024, Day04, Input, 2, 1930);
|
||||
|
||||
READ_INPUT(input)
|
||||
{
|
||||
return Input::ReadArray2D(input);
|
||||
}
|
||||
|
||||
OUTPUT1(input)
|
||||
{
|
||||
int32_t sum = 0;
|
||||
for (int y = 0; y < input.height; y++)
|
||||
{
|
||||
for (int x = 0; x < input.width; x++)
|
||||
{
|
||||
if (y < input.height - 3 && input.Get(x, y) == 'X' && input.Get(x, y + 1) == 'M' &&
|
||||
input.Get(x, y + 2) == 'A' && input.Get(x, y + 3) == 'S')
|
||||
sum++;
|
||||
if (y < input.height - 3 && input.Get(x, y) == 'S' && input.Get(x, y + 1) == 'A' &&
|
||||
input.Get(x, y + 2) == 'M' && input.Get(x, y + 3) == 'X')
|
||||
sum++;
|
||||
if (x < input.width - 3 && input.Get(x, y) == 'X' && input.Get(x + 1, y) == 'M' && input.Get(x + 2, y) == 'A' &&
|
||||
input.Get(x + 3, y) == 'S')
|
||||
sum++;
|
||||
if (x < input.width - 3 && input.Get(x, y) == 'S' && input.Get(x + 1, y) == 'A' && input.Get(x + 2, y) == 'M' &&
|
||||
input.Get(x + 3, y) == 'X')
|
||||
sum++;
|
||||
if (y < input.height - 3 && x < input.width - 3 && input.Get(x, y) == 'X' && input.Get(x + 1, y + 1) == 'M' &&
|
||||
input.Get(x + 2, y + 2) == 'A' && input.Get(x + 3, y + 3) == 'S')
|
||||
sum++;
|
||||
if (y < input.height - 3 && x < input.width - 3 && input.Get(x, y) == 'S' && input.Get(x + 1, y + 1) == 'A' &&
|
||||
input.Get(x + 2, y + 2) == 'M' && input.Get(x + 3, y + 3) == 'X')
|
||||
sum++;
|
||||
if (y < input.height - 3 && x < input.width - 3 && input.Get(x + 3, y) == 'X' &&
|
||||
input.Get(x + 2, y + 1) == 'M' && input.Get(x + 1, y + 2) == 'A' && input.Get(x, y + 3) == 'S')
|
||||
sum++;
|
||||
if (y < input.height - 3 && x < input.width - 3 && input.Get(x + 3, y) == 'S' &&
|
||||
input.Get(x + 2, y + 1) == 'A' && input.Get(x + 1, y + 2) == 'M' && input.Get(x, y + 3) == 'X')
|
||||
sum++;
|
||||
}
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
OUTPUT2(input)
|
||||
{
|
||||
int32_t sum = 0;
|
||||
for (int y = 0; y < input.height - 2; y++)
|
||||
{
|
||||
for (int x = 0; x < input.width - 2; x++)
|
||||
{
|
||||
if (input.Get(x, y) == 'M' && input.Get(x, y + 2) == 'M' && input.Get(x + 1, y + 1) == 'A' &&
|
||||
input.Get(x + 2, y) == 'S' && input.Get(x + 2, y + 2) == 'S')
|
||||
sum++;
|
||||
if (input.Get(x, y) == 'M' && input.Get(x, y + 2) == 'S' && input.Get(x + 1, y + 1) == 'A' &&
|
||||
input.Get(x + 2, y) == 'M' && input.Get(x + 2, y + 2) == 'S')
|
||||
sum++;
|
||||
if (input.Get(x, y) == 'S' && input.Get(x, y + 2) == 'M' && input.Get(x + 1, y + 1) == 'A' &&
|
||||
input.Get(x + 2, y) == 'S' && input.Get(x + 2, y + 2) == 'M')
|
||||
sum++;
|
||||
if (input.Get(x, y) == 'S' && input.Get(x, y + 2) == 'S' && input.Get(x + 1, y + 1) == 'A' &&
|
||||
input.Get(x + 2, y) == 'M' && input.Get(x + 2, y + 2) == 'M')
|
||||
sum++;
|
||||
}
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
#include "common/aoc.h"
|
||||
|
||||
namespace day05
|
||||
{
|
||||
struct Manual
|
||||
{
|
||||
std::vector<std::pair<int, int>> pairs;
|
||||
std::vector<std::vector<int>> pages;
|
||||
};
|
||||
|
||||
REGISTER_DAY(2024, Day05, Manual, int32_t);
|
||||
|
||||
REGISTER_TEST_EXAMPLE(2024, Day05, ExampleInput, 1, 143);
|
||||
REGISTER_TEST(2024, Day05, Input, 1, 5964);
|
||||
REGISTER_TEST_EXAMPLE(2024, Day05, ExampleInput, 2, 123);
|
||||
REGISTER_TEST(2024, Day05, Input, 2, 4719);
|
||||
|
||||
READ_INPUT(input)
|
||||
{
|
||||
std::vector<std::pair<int, int>> pairs;
|
||||
std::string str;
|
||||
while (std::getline(input, str))
|
||||
{
|
||||
if (str.empty())
|
||||
break;
|
||||
|
||||
int i, j;
|
||||
std::stringstream ss{str};
|
||||
ss >> i >> "|" >> j;
|
||||
pairs.emplace_back(i, j);
|
||||
}
|
||||
std::vector<std::vector<int>> pages;
|
||||
while (std::getline(input, str))
|
||||
{
|
||||
std::stringstream ss{str};
|
||||
pages.emplace_back(Input::ReadInts(ss, ','));
|
||||
}
|
||||
return Manual{pairs, pages};
|
||||
}
|
||||
|
||||
std::pair<bool, int> IsValid(const std::vector<int>& input, const std::vector<std::pair<int, int>>& pairs)
|
||||
{
|
||||
for (int i = 0; i < input.size() - 1; i++)
|
||||
{
|
||||
for (const auto& pair : pairs)
|
||||
{
|
||||
if (input[i] == pair.second && input[i + 1] == pair.first)
|
||||
{
|
||||
return {false, i};
|
||||
}
|
||||
}
|
||||
}
|
||||
return {true, 0};
|
||||
}
|
||||
|
||||
std::vector<int> Sort(std::vector<int> input, const std::vector<std::pair<int, int>>& pairs)
|
||||
{
|
||||
bool valid;
|
||||
do
|
||||
{
|
||||
auto [res, index] = IsValid(input, pairs);
|
||||
if (!res)
|
||||
std::swap(input[index], input[index + 1]);
|
||||
valid = res;
|
||||
} while (!valid);
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
OUTPUT1(input)
|
||||
{
|
||||
int32_t sum = 0;
|
||||
for (const auto& man : input.pages)
|
||||
{
|
||||
if (IsValid(man, input.pairs).first)
|
||||
sum += man[man.size() / 2];
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
OUTPUT2(input)
|
||||
{
|
||||
int32_t sum = 0;
|
||||
for (const auto& man : input.pages)
|
||||
{
|
||||
if (!IsValid(man, input.pairs).first)
|
||||
{
|
||||
auto newMan = Sort(man, input.pairs);
|
||||
sum += newMan[newMan.size() / 2];
|
||||
}
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
#include "common/aoc.h"
|
||||
|
||||
namespace day06
|
||||
{
|
||||
REGISTER_DAY(2024, Day06, Array2D<char>, int32_t);
|
||||
|
||||
REGISTER_TEST_EXAMPLE(2024, Day06, ExampleInput, 1, 41);
|
||||
REGISTER_TEST(2024, Day06, Input, 1, 4776);
|
||||
REGISTER_TEST_EXAMPLE(2024, Day06, ExampleInput, 2, 6);
|
||||
REGISTER_TEST(2024, Day06, Input, 2, 1586);
|
||||
|
||||
READ_INPUT(input)
|
||||
{
|
||||
return Input::ReadArray2D(input);
|
||||
}
|
||||
|
||||
bool TestObstacle(const Array2D<char>& map, Index2D obstacle, Index2D startPos, Index2D startDir)
|
||||
{
|
||||
std::set<std::pair<Index2D, Index2D>> visited;
|
||||
Index2D index = startPos;
|
||||
Index2D dir = startDir;
|
||||
|
||||
while (map.IsInside(index) && visited.find(std::pair{index, dir}) == visited.end())
|
||||
{
|
||||
visited.emplace(index, dir);
|
||||
Index2D newIndex{index.x + dir.x, index.y + dir.y};
|
||||
if ((map.IsInside(newIndex) && map.Get(newIndex) == '#') || newIndex == obstacle)
|
||||
{
|
||||
Index2D newDir{-dir.y, dir.x};
|
||||
dir = newDir;
|
||||
}
|
||||
else
|
||||
{
|
||||
index = newIndex;
|
||||
}
|
||||
}
|
||||
return visited.find(std::pair{index, dir}) != visited.end();
|
||||
}
|
||||
|
||||
OUTPUT1(input)
|
||||
{
|
||||
std::set<Index2D> visited;
|
||||
Index2D index = input.Find('^');
|
||||
Index2D dir{0, -1};
|
||||
while (input.IsInside(index))
|
||||
{
|
||||
visited.emplace(index);
|
||||
Index2D newIndex{index.x + dir.x, index.y + dir.y};
|
||||
if (input.IsInside(newIndex) && input.Get(newIndex) == '#')
|
||||
{
|
||||
Index2D newDir{-dir.y, dir.x};
|
||||
dir = newDir;
|
||||
}
|
||||
else
|
||||
{
|
||||
index = newIndex;
|
||||
}
|
||||
}
|
||||
return visited.size();
|
||||
}
|
||||
|
||||
OUTPUT2(input)
|
||||
{
|
||||
std::set<Index2D> visited;
|
||||
Index2D index = input.Find('^');
|
||||
Index2D dir{0, -1};
|
||||
int32_t sum = 0;
|
||||
while (input.IsInside(index))
|
||||
{
|
||||
Index2D newIndex{index.x + dir.x, index.y + dir.y};
|
||||
if (input.IsInside(newIndex) && input.Get(newIndex) == '#')
|
||||
{
|
||||
Index2D newDir{-dir.y, dir.x};
|
||||
dir = newDir;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (visited.count(newIndex) == 0)
|
||||
{
|
||||
if (TestObstacle(input, newIndex, index, dir))
|
||||
sum++;
|
||||
}
|
||||
visited.emplace(index);
|
||||
index = newIndex;
|
||||
}
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
#include "common/aoc.h"
|
||||
|
||||
namespace day07
|
||||
{
|
||||
struct Data
|
||||
{
|
||||
int64_t result;
|
||||
std::vector<int64_t> terms;
|
||||
};
|
||||
|
||||
REGISTER_DAY(2024, Day07, std::vector<Data>, int64_t);
|
||||
|
||||
REGISTER_TEST_EXAMPLE(2024, Day07, ExampleInput, 1, 3749);
|
||||
REGISTER_TEST(2024, Day07, Input, 1, 945512582195);
|
||||
REGISTER_TEST_EXAMPLE(2024, Day07, ExampleInput, 2, 11387);
|
||||
REGISTER_TEST(2024, Day07, Input, 2, 271691107779347);
|
||||
|
||||
READ_INPUT(input)
|
||||
{
|
||||
std::vector<Data> datas;
|
||||
std::string str;
|
||||
while (std::getline(input, str))
|
||||
{
|
||||
std::stringstream ss{str};
|
||||
Data data;
|
||||
ss >> data.result >> ": ";
|
||||
while (std::getline(ss, str, ' '))
|
||||
{
|
||||
data.terms.emplace_back(std::stoll(str));
|
||||
}
|
||||
datas.emplace_back(data);
|
||||
}
|
||||
return datas;
|
||||
}
|
||||
|
||||
bool CanCalculateResultP1(const Data& data, int index, int64_t current)
|
||||
{
|
||||
if (index >= data.terms.size())
|
||||
return data.result == current;
|
||||
if (index == 0)
|
||||
return CanCalculateResultP1(data, index + 1, data.terms[index]);
|
||||
|
||||
if (CanCalculateResultP1(data, index + 1, current + data.terms[index]))
|
||||
return true;
|
||||
else if (CanCalculateResultP1(data, index + 1, current * data.terms[index]))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
int64_t Concat(int64_t i1, int64_t i2)
|
||||
{
|
||||
int64_t base = 10;
|
||||
while (i2 >= base) base *= 10;
|
||||
return i1 * base + i2;
|
||||
}
|
||||
|
||||
bool CanCalculateResultP2(const Data& data, int index, int64_t current)
|
||||
{
|
||||
if (index >= data.terms.size())
|
||||
return data.result == current;
|
||||
if (index == 0)
|
||||
return CanCalculateResultP2(data, index + 1, data.terms[index]);
|
||||
|
||||
if (CanCalculateResultP2(data, index + 1, current + data.terms[index]))
|
||||
return true;
|
||||
else if (CanCalculateResultP2(data, index + 1, current * data.terms[index]))
|
||||
return true;
|
||||
else if (CanCalculateResultP2(data, index + 1, Concat(current, data.terms[index])))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
OUTPUT1(input)
|
||||
{
|
||||
int64_t sum = 0;
|
||||
for (const auto& data : input)
|
||||
{
|
||||
if (CanCalculateResultP1(data, 0, 0))
|
||||
sum += data.result;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
OUTPUT2(input)
|
||||
{
|
||||
int64_t sum = 0;
|
||||
for (const auto& data : input)
|
||||
{
|
||||
if (CanCalculateResultP2(data, 0, 0))
|
||||
sum += data.result;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
#include "common/aoc.h"
|
||||
|
||||
namespace day08
|
||||
{
|
||||
struct Data
|
||||
{
|
||||
std::map<char, std::vector<Index2D>> map;
|
||||
int width;
|
||||
int height;
|
||||
};
|
||||
|
||||
REGISTER_DAY(2024, Day08, Data, int32_t);
|
||||
|
||||
REGISTER_TEST_EXAMPLE(2024, Day08, ExampleInput, 1, 14);
|
||||
REGISTER_TEST(2024, Day08, Input, 1, 244);
|
||||
REGISTER_TEST_EXAMPLE(2024, Day08, ExampleInput, 2, 34);
|
||||
REGISTER_TEST(2024, Day08, Input, 2, 912);
|
||||
|
||||
READ_INPUT(input)
|
||||
{
|
||||
Data data;
|
||||
std::string str;
|
||||
int y = 0;
|
||||
while (std::getline(input, str))
|
||||
{
|
||||
for (int i = 0; i < str.size(); i++)
|
||||
{
|
||||
if (str[i] != '.')
|
||||
data.map[str[i]].emplace_back(Index2D{i, y});
|
||||
}
|
||||
data.width = str.size();
|
||||
y++;
|
||||
}
|
||||
data.height = y;
|
||||
return data;
|
||||
}
|
||||
|
||||
OUTPUT1(input)
|
||||
{
|
||||
std::set<Index2D> antinodes;
|
||||
int32_t sum = 0;
|
||||
for (auto& [freq, locations] : input.map)
|
||||
{
|
||||
for (int i = 0; i < locations.size(); i++)
|
||||
{
|
||||
for (int j = i + 1; j < locations.size(); j++)
|
||||
{
|
||||
Index2D diff = locations[i] - locations[j];
|
||||
Index2D newPos1 = locations[i] + diff;
|
||||
Index2D newPos2 = locations[j] - diff;
|
||||
if (newPos1.x >= 0 && newPos1.x < input.width && newPos1.y >= 0 && newPos1.y < input.height)
|
||||
antinodes.emplace(newPos1);
|
||||
if (newPos2.x >= 0 && newPos2.x < input.width && newPos2.y >= 0 && newPos2.y < input.height)
|
||||
antinodes.emplace(newPos2);
|
||||
}
|
||||
}
|
||||
}
|
||||
return antinodes.size();
|
||||
}
|
||||
|
||||
OUTPUT2(input)
|
||||
{
|
||||
std::set<Index2D> antinodes;
|
||||
for (auto& [freq, locations] : input.map)
|
||||
{
|
||||
for (int i = 0; i < locations.size(); i++)
|
||||
{
|
||||
for (int j = i + 1; j < locations.size(); j++)
|
||||
{
|
||||
Index2D diff = locations[i] - locations[j];
|
||||
int offset = 0;
|
||||
while (true)
|
||||
{
|
||||
Index2D newPos = locations[i] + diff * offset;
|
||||
if (newPos.x < 0 || newPos.x >= input.width || newPos.y < 0 || newPos.y >= input.height)
|
||||
break;
|
||||
antinodes.emplace(newPos);
|
||||
offset++;
|
||||
}
|
||||
offset = 0;
|
||||
while (true)
|
||||
{
|
||||
Index2D newPos = locations[j] - diff * offset;
|
||||
if (newPos.x < 0 || newPos.x >= input.width || newPos.y < 0 || newPos.y >= input.height)
|
||||
break;
|
||||
antinodes.emplace(newPos);
|
||||
offset++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return antinodes.size();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
#include "common/aoc.h"
|
||||
|
||||
namespace day09
|
||||
{
|
||||
REGISTER_DAY(2024, Day09, std::vector<int>, int64_t);
|
||||
|
||||
REGISTER_TEST_EXAMPLE(2024, Day09, ExampleInput, 1, 1928);
|
||||
REGISTER_TEST(2024, Day09, Input, 1, 6283404590840);
|
||||
REGISTER_TEST_EXAMPLE(2024, Day09, ExampleInput, 2, 2858);
|
||||
REGISTER_TEST(2024, Day09, Input, 2, 6304576012713);
|
||||
|
||||
READ_INPUT(input)
|
||||
{
|
||||
std::string str;
|
||||
std::getline(input, str);
|
||||
if (str.size() % 2 == 0)
|
||||
str.pop_back();
|
||||
std::vector<int> disk;
|
||||
std::transform(str.begin(), str.end(), std::back_inserter(disk), [](char c) { return c - '0'; });
|
||||
return disk;
|
||||
}
|
||||
|
||||
struct File
|
||||
{
|
||||
int64_t pos;
|
||||
int64_t size;
|
||||
int64_t id;
|
||||
};
|
||||
|
||||
OUTPUT1(input)
|
||||
{
|
||||
int64_t sum = 0;
|
||||
std::vector<std::pair<int, int>> resMemory;
|
||||
resMemory.emplace_back(input[0], 0);
|
||||
int currentFreeIndex = 1;
|
||||
int currentFreeMemory = input[currentFreeIndex];
|
||||
int currentMemoryIndex = input.size() - 1;
|
||||
int currentMemoryToMove = input[currentMemoryIndex];
|
||||
while (true)
|
||||
{
|
||||
if (currentMemoryToMove <= currentFreeMemory)
|
||||
{
|
||||
resMemory.emplace_back(currentMemoryToMove, currentMemoryIndex / 2);
|
||||
currentFreeMemory -= currentMemoryToMove;
|
||||
currentMemoryIndex -= 2;
|
||||
currentMemoryToMove = input[currentMemoryIndex];
|
||||
if (currentMemoryIndex < currentFreeIndex)
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
resMemory.emplace_back(currentFreeMemory, currentMemoryIndex / 2);
|
||||
currentMemoryToMove -= currentFreeMemory;
|
||||
currentFreeMemory = 0;
|
||||
}
|
||||
|
||||
if (currentFreeMemory == 0)
|
||||
{
|
||||
if (currentFreeIndex + 1 == currentMemoryIndex)
|
||||
{
|
||||
resMemory.back().first += currentMemoryToMove;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
resMemory.emplace_back(input[currentFreeIndex + 1], (currentFreeIndex + 1) / 2);
|
||||
currentFreeIndex += 2;
|
||||
currentFreeMemory = input[currentFreeIndex];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int64_t pos = 0;
|
||||
for (auto [count, id] : resMemory)
|
||||
{
|
||||
// Based on sum of integer formula:
|
||||
// S = numberOfIntegers * (firstNumber + lastNumber) / 2
|
||||
int64_t firstNumber = pos;
|
||||
int64_t lastNumber = pos + count - 1;
|
||||
sum += count * (firstNumber + lastNumber) / 2 * id;
|
||||
pos += count;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
OUTPUT2(input)
|
||||
{
|
||||
int64_t sum = 0;
|
||||
std::map<int64_t, int64_t> idToPos;
|
||||
std::vector<File> resMemory;
|
||||
std::vector<std::pair<int64_t, int64_t>> freeMemory;
|
||||
int pos = 0;
|
||||
for (int i = 0; i < input.size(); i += 2)
|
||||
{
|
||||
idToPos.emplace(i / 2, pos);
|
||||
pos += input[i];
|
||||
if (i != input.size() - 1)
|
||||
{
|
||||
freeMemory.emplace_back(pos, input[i + 1]);
|
||||
pos += input[i + 1];
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = input.size() - 1; i >= 0; i -= 2)
|
||||
{
|
||||
int fileSize = input[i];
|
||||
int fileId = i / 2;
|
||||
int filePos = idToPos[fileId];
|
||||
|
||||
for (int j = 0; j < freeMemory.size(); j++)
|
||||
{
|
||||
auto& [freeMemoryPos, freeMemorySize] = freeMemory[j];
|
||||
if (freeMemoryPos > filePos)
|
||||
{
|
||||
// Couldn't find a suitable place for the file, don't move it
|
||||
resMemory.emplace_back(File{filePos, fileSize, fileId});
|
||||
break;
|
||||
}
|
||||
|
||||
if (freeMemorySize >= fileSize)
|
||||
{
|
||||
resMemory.emplace_back(File{freeMemoryPos, fileSize, fileId});
|
||||
freeMemorySize -= fileSize;
|
||||
freeMemoryPos += fileSize;
|
||||
if (freeMemorySize == 0)
|
||||
freeMemory.erase(freeMemory.begin() + j);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& file : resMemory)
|
||||
{
|
||||
// Based on sum of integer formula:
|
||||
// S = numberOfIntegers * (firstNumber + lastNumber) / 2
|
||||
int64_t firstNumber = file.pos;
|
||||
int64_t lastNumber = file.pos + file.size - 1;
|
||||
sum += file.size * (firstNumber + lastNumber) / 2 * file.id;
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
#include "common/aoc.h"
|
||||
|
||||
namespace day10
|
||||
{
|
||||
REGISTER_DAY(2024, Day10, Array2D<int>, int32_t);
|
||||
|
||||
REGISTER_TEST_EXAMPLE(2024, Day10, ExampleInput, 1, 36);
|
||||
REGISTER_TEST(2024, Day10, Input, 1, 786);
|
||||
REGISTER_TEST_EXAMPLE(2024, Day10, ExampleInput, 2, 81);
|
||||
REGISTER_TEST(2024, Day10, Input, 2, 1722);
|
||||
|
||||
READ_INPUT(input)
|
||||
{
|
||||
return Input::ReadDigitsAsArray2D(input);
|
||||
}
|
||||
|
||||
void GetTops(const Array2D<int>& map, Index2D pos, std::set<Index2D>& visited)
|
||||
{
|
||||
int val = map.Get(pos);
|
||||
if (val == 9)
|
||||
{
|
||||
visited.emplace(pos);
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<Index2D> indices{Index2D{-1, 0}, Index2D{1, 0}, Index2D{0, -1}, Index2D{0, 1}};
|
||||
for (auto index : indices)
|
||||
{
|
||||
if (map.IsInside(pos + index) && map.Get(pos + index) == val + 1)
|
||||
GetTops(map, pos + index, visited);
|
||||
}
|
||||
}
|
||||
|
||||
int CountPaths(const Array2D<int>& map, Index2D pos)
|
||||
{
|
||||
int val = map.Get(pos);
|
||||
if (val == 9)
|
||||
return 1;
|
||||
|
||||
int paths = 0;
|
||||
std::vector<Index2D> indices{Index2D{-1, 0}, Index2D{1, 0}, Index2D{0, -1}, Index2D{0, 1}};
|
||||
for (auto index : indices)
|
||||
{
|
||||
if (map.IsInside(pos + index) && map.Get(pos + index) == val + 1)
|
||||
paths += CountPaths(map, pos + index);
|
||||
}
|
||||
|
||||
return paths;
|
||||
}
|
||||
|
||||
OUTPUT1(input)
|
||||
{
|
||||
int32_t sum = 0;
|
||||
for (int y = 0; y < input.height; y++)
|
||||
{
|
||||
for (int x = 0; x < input.width; x++)
|
||||
{
|
||||
if (input.Get(x, y) == 0)
|
||||
{
|
||||
std::set<Index2D> visited;
|
||||
GetTops(input, Index2D{x, y}, visited);
|
||||
sum += visited.size();
|
||||
}
|
||||
}
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
OUTPUT2(input)
|
||||
{
|
||||
int32_t sum = 0;
|
||||
for (int y = 0; y < input.height; y++)
|
||||
{
|
||||
for (int x = 0; x < input.width; x++)
|
||||
{
|
||||
if (input.Get(x, y) == 0)
|
||||
{
|
||||
sum += CountPaths(input, Index2D{x, y});
|
||||
}
|
||||
}
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
#include "common/aoc.h"
|
||||
|
||||
namespace day11
|
||||
{
|
||||
using Stones = std::map<int64_t, int64_t>;
|
||||
REGISTER_DAY(2024, Day11, Stones, int64_t);
|
||||
|
||||
REGISTER_TEST_EXAMPLE(2024, Day11, ExampleInput, 1, 55312);
|
||||
REGISTER_TEST(2024, Day11, Input, 1, 189167);
|
||||
REGISTER_TEST_EXAMPLE(2024, Day11, ExampleInput, 2, 65601038650482);
|
||||
REGISTER_TEST(2024, Day11, Input, 2, 225253278506288);
|
||||
|
||||
READ_INPUT(input)
|
||||
{
|
||||
Stones stones;
|
||||
for (auto i : Input::ReadInt64s(input, ' ')) stones[i]++;
|
||||
return stones;
|
||||
}
|
||||
|
||||
int logi10(int64_t i)
|
||||
{
|
||||
int log = 1;
|
||||
int64_t base = 10;
|
||||
while (i >= base)
|
||||
{
|
||||
base *= 10;
|
||||
log++;
|
||||
}
|
||||
return log;
|
||||
}
|
||||
|
||||
int64_t pow10(int i)
|
||||
{
|
||||
int64_t pow = 1;
|
||||
|
||||
for (int j = 0; j < i; j++) pow *= 10;
|
||||
|
||||
return pow;
|
||||
}
|
||||
|
||||
std::pair<int64_t, int64_t> split(int64_t i)
|
||||
{
|
||||
int log = logi10(i);
|
||||
int64_t pow = pow10(log / 2);
|
||||
|
||||
return {i / pow, i % pow};
|
||||
}
|
||||
|
||||
void Step(std::map<int64_t, int64_t>& stones)
|
||||
{
|
||||
std::map<int64_t, int64_t> next;
|
||||
|
||||
for (auto [cur, count] : stones)
|
||||
{
|
||||
if (cur == 0)
|
||||
{
|
||||
next[1] += count;
|
||||
}
|
||||
else if (logi10(cur) % 2 == 0)
|
||||
{
|
||||
auto [i1, i2] = split(cur);
|
||||
next[i1] += count;
|
||||
next[i2] += count;
|
||||
}
|
||||
else
|
||||
{
|
||||
next[cur * 2024] += count;
|
||||
}
|
||||
}
|
||||
stones = std::move(next);
|
||||
}
|
||||
|
||||
int64_t CalculateStones(const std::map<int64_t, int64_t>& stones, int iterations)
|
||||
{
|
||||
std::map<int64_t, int64_t> cpy = stones;
|
||||
|
||||
for (int i = 0; i < iterations; i++) Step(cpy);
|
||||
|
||||
int64_t sum = 0;
|
||||
for (auto& [cur, count] : cpy)
|
||||
{
|
||||
sum += count;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
OUTPUT1(input)
|
||||
{
|
||||
return CalculateStones(input, 25);
|
||||
}
|
||||
|
||||
OUTPUT2(input)
|
||||
{
|
||||
return CalculateStones(input, 75);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
#include "common/aoc.h"
|
||||
|
||||
namespace day12
|
||||
{
|
||||
REGISTER_DAY(2024, Day12, Array2D<char>, int);
|
||||
|
||||
REGISTER_TEST_EXAMPLE(2024, Day12, ExampleInput, 1, 1930);
|
||||
REGISTER_TEST(2024, Day12, Input, 1, 1550156);
|
||||
REGISTER_TEST_EXAMPLE(2024, Day12, ExampleInput, 2, 1206);
|
||||
REGISTER_TEST(2024, Day12, Input, 2, 946084);
|
||||
|
||||
READ_INPUT(input)
|
||||
{
|
||||
return Input::ReadArray2D(input);
|
||||
}
|
||||
|
||||
void CalculateAreaAndPerimiter(const Array2D<char>& map,
|
||||
Index2D position,
|
||||
std::set<Index2D>& totalVisited,
|
||||
std::set<Index2D>& area,
|
||||
std::set<std::pair<Index2D, Index2D>>& perimeter)
|
||||
{
|
||||
char c = map.Get(position);
|
||||
std::stack<Index2D> toEvaluate;
|
||||
toEvaluate.emplace(position);
|
||||
area.emplace(position);
|
||||
while (!toEvaluate.empty())
|
||||
{
|
||||
Index2D current = toEvaluate.top();
|
||||
toEvaluate.pop();
|
||||
totalVisited.emplace(current);
|
||||
|
||||
for (auto& dir : Helper::GetNeighborDirections())
|
||||
{
|
||||
Index2D newPos = current + dir;
|
||||
if (area.count(newPos) == 0)
|
||||
{
|
||||
if (map.IsInside(newPos) && map.Get(newPos) == c)
|
||||
{
|
||||
toEvaluate.emplace(newPos);
|
||||
area.emplace(newPos);
|
||||
}
|
||||
else
|
||||
perimeter.emplace(current, dir);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RemovePerimetersNextToPos(std::set<std::pair<Index2D, Index2D>>& perimeter,
|
||||
Index2D pos,
|
||||
Index2D normal,
|
||||
Index2D dir)
|
||||
{
|
||||
Index2D next = pos + dir;
|
||||
auto it = perimeter.find({next, normal});
|
||||
while (it != perimeter.end())
|
||||
{
|
||||
perimeter.erase(it);
|
||||
next = next + dir;
|
||||
it = perimeter.find({next, normal});
|
||||
}
|
||||
}
|
||||
|
||||
int CalculatePerimeterSideSize(std::set<std::pair<Index2D, Index2D>>& perimeter)
|
||||
{
|
||||
int perimeterSize = 0;
|
||||
while (!perimeter.empty())
|
||||
{
|
||||
auto [index, dir] = *perimeter.begin();
|
||||
perimeter.erase(perimeter.begin());
|
||||
perimeterSize++;
|
||||
|
||||
RemovePerimetersNextToPos(perimeter, index, dir, Index2D{dir.y, dir.x});
|
||||
RemovePerimetersNextToPos(perimeter, index, dir, Index2D{-dir.y, -dir.x});
|
||||
}
|
||||
return perimeterSize;
|
||||
}
|
||||
|
||||
OUTPUT1(input)
|
||||
{
|
||||
int sum = 0;
|
||||
std::set<Index2D> visited;
|
||||
for (auto it = input.begin(); it != input.end(); it++)
|
||||
{
|
||||
Index2D index = it.index;
|
||||
if (visited.count(index) == 0)
|
||||
{
|
||||
std::set<Index2D> area;
|
||||
std::set<std::pair<Index2D, Index2D>> perimeter;
|
||||
CalculateAreaAndPerimiter(input, it.index, visited, area, perimeter);
|
||||
|
||||
sum += perimeter.size() * area.size();
|
||||
}
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
OUTPUT2(input)
|
||||
{
|
||||
int sum = 0;
|
||||
std::set<Index2D> visited;
|
||||
for (auto it = input.begin(); it != input.end(); it++)
|
||||
{
|
||||
if (visited.count(it.index) == 0)
|
||||
{
|
||||
std::set<Index2D> area;
|
||||
std::set<std::pair<Index2D, Index2D>> perimeter;
|
||||
CalculateAreaAndPerimiter(input, it.index, visited, area, perimeter);
|
||||
int perimeterSize = CalculatePerimeterSideSize(perimeter);
|
||||
|
||||
sum += perimeterSize * area.size();
|
||||
}
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
#include "common/aoc.h"
|
||||
|
||||
namespace day13
|
||||
{
|
||||
struct ClawMachine
|
||||
{
|
||||
int64_t buttonAX;
|
||||
int64_t buttonAY;
|
||||
int64_t buttonBX;
|
||||
int64_t buttonBY;
|
||||
int64_t prizeX;
|
||||
int64_t prizeY;
|
||||
};
|
||||
|
||||
REGISTER_DAY(2024, Day13, std::vector<ClawMachine>, int64_t);
|
||||
|
||||
REGISTER_TEST_EXAMPLE(2024, Day13, ExampleInput, 1, 480);
|
||||
REGISTER_TEST(2024, Day13, Input, 1, 26005);
|
||||
REGISTER_TEST_EXAMPLE(2024, Day13, ExampleInput, 2, 875318608908);
|
||||
REGISTER_TEST(2024, Day13, Input, 2, 105620095782547);
|
||||
|
||||
READ_INPUT(input)
|
||||
{
|
||||
std::vector<ClawMachine> clawMachines;
|
||||
std::string str;
|
||||
while (std::getline(input, str))
|
||||
{
|
||||
ClawMachine machine;
|
||||
std::stringstream ss{str};
|
||||
ss >> "Button A: X+" >> machine.buttonAX >> ", Y+" >> machine.buttonAY;
|
||||
|
||||
std::getline(input, str);
|
||||
ss = std::stringstream{str};
|
||||
ss >> "Button B: X+" >> machine.buttonBX >> ", Y+" >> machine.buttonBY;
|
||||
|
||||
std::getline(input, str);
|
||||
ss = std::stringstream{str};
|
||||
ss >> "Prize: X=" >> machine.prizeX >> ", Y=" >> machine.prizeY;
|
||||
std::getline(input, str);
|
||||
clawMachines.emplace_back(machine);
|
||||
}
|
||||
return clawMachines;
|
||||
}
|
||||
|
||||
int64_t GetCost(const ClawMachine& machine)
|
||||
{
|
||||
// Solve
|
||||
// aX * a + bX * b = pX
|
||||
// aY * a + bY * b = pY
|
||||
|
||||
// aY * aX * a + aY * bX * b = aY * pX
|
||||
// -aY * aX * a + -aX * bY * b = -aX * pY
|
||||
|
||||
// (aY * bX * b) + (-aX * bY * b) = aY * pX + (-aX * pY)
|
||||
// (aY * bX - aX * bY) * b = aY * pX - aX * pY
|
||||
// b = (aY * pX - aX * pY) / (aY * bX - aX * bY)
|
||||
// a = (pX - bX * b) / aX
|
||||
|
||||
int64_t aYbX = machine.buttonAY * machine.buttonBX;
|
||||
int64_t aYpX = machine.buttonAY * machine.prizeX;
|
||||
|
||||
int64_t aXbY = machine.buttonAX * machine.buttonBY;
|
||||
int64_t aXpY = machine.buttonAX * machine.prizeY;
|
||||
|
||||
if (aYbX - aXbY == 0)
|
||||
{
|
||||
std::cerr << "Multiple solutions" << std::endl;
|
||||
}
|
||||
else if ((aYpX - aXpY) % (aYbX - aXbY) == 0) // integer solution exists
|
||||
{
|
||||
int64_t b = (aYpX - aXpY) / (aYbX - aXbY);
|
||||
int64_t a = (machine.prizeX - b * machine.buttonBX) / machine.buttonAX;
|
||||
if (a >= 0 && b >= 0)
|
||||
return b + a * 3;
|
||||
}
|
||||
return 0; // No solution
|
||||
}
|
||||
|
||||
OUTPUT1(input)
|
||||
{
|
||||
int64_t sum = 0;
|
||||
for (auto& machine : input)
|
||||
{
|
||||
sum += GetCost(machine);
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
OUTPUT2(input)
|
||||
{
|
||||
int64_t sum = 0;
|
||||
for (auto machine : input)
|
||||
{
|
||||
machine.prizeX += 10000000000000;
|
||||
machine.prizeY += 10000000000000;
|
||||
sum += GetCost(machine);
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
#include "common/aoc.h"
|
||||
|
||||
namespace day14
|
||||
{
|
||||
struct Robot
|
||||
{
|
||||
Index2D pos;
|
||||
Index2D vel;
|
||||
};
|
||||
|
||||
REGISTER_DAY(2024, Day14, std::vector<Robot>, int32_t);
|
||||
|
||||
REGISTER_TEST_EXAMPLE(2024, Day14, ExampleInput, 1, 12);
|
||||
REGISTER_TEST(2024, Day14, Input, 1, 228421332);
|
||||
// REGISTER_TEST_EXAMPLE(2024, Day14, ExampleInput, 2, 31);
|
||||
REGISTER_TEST(2024, Day14, Input, 2, 7790);
|
||||
|
||||
READ_INPUT(input)
|
||||
{
|
||||
std::vector<Robot> robots;
|
||||
std::string str;
|
||||
while (std::getline(input, str))
|
||||
{
|
||||
Robot robot;
|
||||
std::stringstream ss{str};
|
||||
ss >> "p=" >> robot.pos.x >> "," >> robot.pos.y >> "v=" >> robot.vel.x >> "," >> robot.vel.y;
|
||||
robots.emplace_back(robot);
|
||||
}
|
||||
return robots;
|
||||
}
|
||||
|
||||
OUTPUT1(input)
|
||||
{
|
||||
int width = 101;
|
||||
int height = 103;
|
||||
if (isExample)
|
||||
{
|
||||
width = 11;
|
||||
height = 7;
|
||||
}
|
||||
|
||||
int a{0}, b{0}, c{0}, d{0};
|
||||
for (auto& robot : input)
|
||||
{
|
||||
Index2D endPos = robot.pos + robot.vel * 100;
|
||||
endPos.x = (endPos.x % width + width) % width;
|
||||
endPos.y = (endPos.y % height + height) % height;
|
||||
if (endPos.x < width / 2 && endPos.y < height / 2)
|
||||
a++;
|
||||
if (endPos.x < width / 2 && endPos.y > height / 2)
|
||||
b++;
|
||||
if (endPos.x > width / 2 && endPos.y < height / 2)
|
||||
c++;
|
||||
if (endPos.x > width / 2 && endPos.y > height / 2)
|
||||
d++;
|
||||
}
|
||||
|
||||
return a * b * c * d;
|
||||
}
|
||||
|
||||
int GetStepCoord(const std::vector<Robot>& robots, int length, int dimension)
|
||||
{
|
||||
int maxIndex = 0;
|
||||
int maxNeighbors = 0;
|
||||
for (int i = 1; i <= length; i++)
|
||||
{
|
||||
std::vector<int> amounts(length, 0);
|
||||
for (const auto& robot : robots)
|
||||
{
|
||||
int endPos = robot.pos[dimension] + robot.vel[dimension] * i;
|
||||
endPos = (endPos % length + length) % length;
|
||||
amounts[endPos]++;
|
||||
}
|
||||
|
||||
int neighbors = 0;
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
neighbors += amounts[i] * (amounts[(i + 1) % length] + amounts[(i + length - 1) % length]);
|
||||
}
|
||||
if (neighbors > maxNeighbors)
|
||||
{
|
||||
maxNeighbors = neighbors;
|
||||
maxIndex = i;
|
||||
}
|
||||
}
|
||||
return maxIndex;
|
||||
}
|
||||
|
||||
OUTPUT2(input)
|
||||
{
|
||||
int width = 101;
|
||||
int height = 103;
|
||||
int stepX = GetStepCoord(input, width, 0);
|
||||
int stepY = GetStepCoord(input, height, 1);
|
||||
|
||||
return Helper::ChineseRemainderTheorem({width, height}, {stepX, stepY});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
#include "common/aoc.h"
|
||||
|
||||
namespace day15
|
||||
{
|
||||
struct Map
|
||||
{
|
||||
Array2D<char> map;
|
||||
std::string input;
|
||||
};
|
||||
|
||||
REGISTER_DAY(2024, Day15, Map, int64_t);
|
||||
|
||||
REGISTER_TEST_EXAMPLE(2024, Day15, ExampleInput, 1, 10092);
|
||||
REGISTER_TEST(2024, Day15, Input, 1, 1526673);
|
||||
REGISTER_TEST_EXAMPLE(2024, Day15, ExampleInput, 2, 9021);
|
||||
REGISTER_TEST(2024, Day15, Input, 2, 1535509);
|
||||
|
||||
READ_INPUT(input)
|
||||
{
|
||||
Map map;
|
||||
map.map = Input::ReadArray2D(input);
|
||||
|
||||
std::string str;
|
||||
while (std::getline(input, str)) map.input += str;
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
void Move(Array2D<char>& map, Index2D boxPos, Index2D dir)
|
||||
{
|
||||
if (dir.x == 0)
|
||||
{
|
||||
char leftC = map.Get(boxPos.x, boxPos.y + dir.y);
|
||||
if (leftC == '[')
|
||||
Move(map, Index2D{boxPos.x, boxPos.y + dir.y}, dir);
|
||||
if (leftC == ']')
|
||||
Move(map, Index2D{boxPos.x - 1, boxPos.y + dir.y}, dir);
|
||||
|
||||
char rightC = map.Get(boxPos.x + 1, boxPos.y + dir.y);
|
||||
if (rightC == '[')
|
||||
Move(map, Index2D{boxPos.x + 1, boxPos.y + dir.y}, dir);
|
||||
if (rightC == ']')
|
||||
Move(map, Index2D{boxPos.x, boxPos.y + dir.y}, dir);
|
||||
|
||||
map.Set(boxPos.x, boxPos.y + dir.y, '[');
|
||||
map.Set(boxPos.x + 1, boxPos.y + dir.y, ']');
|
||||
map.Set(boxPos.x, boxPos.y, '.');
|
||||
map.Set(boxPos.x + 1, boxPos.y, '.');
|
||||
}
|
||||
else
|
||||
{
|
||||
if (map.Get(boxPos.x + dir.x * 2, boxPos.y) == '[')
|
||||
Move(map, Index2D{boxPos.x + dir.x * 2, boxPos.y}, dir);
|
||||
map.Set(boxPos.x + dir.x, boxPos.y, '[');
|
||||
map.Set(boxPos.x + dir.x + 1, boxPos.y, ']');
|
||||
}
|
||||
}
|
||||
|
||||
bool CanMove(const Array2D<char>& map, Index2D boxPos, Index2D dir);
|
||||
|
||||
bool CanMoveSide(const Array2D<char>& map, Index2D boxSidePos, Index2D dir)
|
||||
{
|
||||
char c = map[boxSidePos];
|
||||
if (c == '.')
|
||||
return true;
|
||||
else if (c == '[')
|
||||
return CanMove(map, Index2D{boxSidePos.x, boxSidePos.y}, dir);
|
||||
else if (c == ']')
|
||||
return CanMove(map, Index2D{boxSidePos.x - 1, boxSidePos.y}, dir);
|
||||
return false;
|
||||
}
|
||||
|
||||
// boxPos is position of [
|
||||
bool CanMove(const Array2D<char>& map, Index2D boxPos, Index2D dir)
|
||||
{
|
||||
if (dir.x == 0)
|
||||
{
|
||||
bool canMoveLeftSide = CanMoveSide(map, Index2D{boxPos.x, boxPos.y + dir.y}, dir);
|
||||
bool canMoveRightSide = CanMoveSide(map, Index2D{boxPos.x + 1, boxPos.y + dir.y}, dir);
|
||||
return canMoveLeftSide && canMoveRightSide;
|
||||
}
|
||||
else
|
||||
{
|
||||
Index2D pos = boxPos + dir;
|
||||
while (true)
|
||||
{
|
||||
char n = map[pos];
|
||||
|
||||
if (n == '.')
|
||||
return true;
|
||||
else if (n == '#')
|
||||
return false;
|
||||
|
||||
pos = pos + dir;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int64_t CalculateResult(const Array2D<char>& map)
|
||||
{
|
||||
int64_t sum = 0;
|
||||
for (auto it = map.begin(); it != map.end(); it++)
|
||||
if (*it == 'O' || *it == '[')
|
||||
sum += it.index.x + it.index.y * 100;
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
OUTPUT1(input)
|
||||
{
|
||||
Map cpy = input;
|
||||
Index2D position = cpy.map.Find('@');
|
||||
for (auto& dirC : cpy.input)
|
||||
{
|
||||
Index2D dir = Helper::GetDirection(dirC);
|
||||
|
||||
char nextChar = cpy.map[position + dir];
|
||||
if (nextChar == '.')
|
||||
{
|
||||
cpy.map[position] = '.';
|
||||
cpy.map[position + dir] = '@';
|
||||
position = position + dir;
|
||||
}
|
||||
else if (nextChar == 'O')
|
||||
{
|
||||
Index2D pos = position + dir;
|
||||
while (true)
|
||||
{
|
||||
char n = cpy.map[pos];
|
||||
if (n == '.')
|
||||
{
|
||||
cpy.map[position] = '.';
|
||||
cpy.map[position + dir] = '@';
|
||||
cpy.map[pos] = 'O';
|
||||
position = position + dir;
|
||||
break;
|
||||
}
|
||||
else if (n == '#')
|
||||
break;
|
||||
pos = pos + dir;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return CalculateResult(cpy.map);
|
||||
}
|
||||
|
||||
OUTPUT2(input)
|
||||
{
|
||||
Array2D<char> map{input.map.width * 2, input.map.height, '.'};
|
||||
for (auto it = input.map.begin(); it != input.map.end(); it++)
|
||||
{
|
||||
if (*it == 'O')
|
||||
{
|
||||
map.Set(it.index.x * 2, it.index.y, '[');
|
||||
map.Set(it.index.x * 2 + 1, it.index.y, ']');
|
||||
}
|
||||
else if (*it == '#')
|
||||
{
|
||||
map.Set(it.index.x * 2, it.index.y, '#');
|
||||
map.Set(it.index.x * 2 + 1, it.index.y, '#');
|
||||
}
|
||||
else if (*it == '@')
|
||||
{
|
||||
map.Set(it.index.x * 2, it.index.y, '@');
|
||||
}
|
||||
}
|
||||
|
||||
Index2D position = map.Find('@');
|
||||
for (auto& dirC : input.input)
|
||||
{
|
||||
Index2D dir = Helper::GetDirection(dirC);
|
||||
|
||||
char nextChar = map[position + dir];
|
||||
if (nextChar == '.')
|
||||
{
|
||||
map[position] = '.';
|
||||
map[position + dir] = '@';
|
||||
position = position + dir;
|
||||
}
|
||||
else if (nextChar == ']' || nextChar == '[')
|
||||
{
|
||||
Index2D boxPos = position + dir;
|
||||
if (nextChar == ']')
|
||||
boxPos.x -= 1;
|
||||
if (CanMove(map, boxPos, dir))
|
||||
{
|
||||
Move(map, boxPos, dir);
|
||||
map[position] = '.';
|
||||
map[position + dir] = '@';
|
||||
position = position + dir;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return CalculateResult(map);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
#include "common/aoc.h"
|
||||
|
||||
namespace day16
|
||||
{
|
||||
REGISTER_DAY(2024, Day16, Array2D<char>, int32_t);
|
||||
|
||||
REGISTER_TEST_EXAMPLE(2024, Day16, ExampleInput, 1, 7036);
|
||||
REGISTER_TEST(2024, Day16, Input, 1, 72428);
|
||||
REGISTER_TEST_EXAMPLE(2024, Day16, ExampleInput, 2, 45);
|
||||
REGISTER_TEST(2024, Day16, Input, 2, 456);
|
||||
|
||||
READ_INPUT(input)
|
||||
{
|
||||
return Input::ReadArray2D(input);
|
||||
}
|
||||
|
||||
std::vector<std::pair<int, std::pair<Index2D, Index2D>>> Branch(const Array2D<char>& map,
|
||||
const std::pair<Index2D, Index2D>& state)
|
||||
{
|
||||
std::vector<std::pair<int, std::pair<Index2D, Index2D>>> paths;
|
||||
if (map.Get(state.first + state.second) != '#')
|
||||
paths.emplace_back(1, std::pair{state.first + state.second, state.second});
|
||||
|
||||
Index2D dir2 = Index2D{state.second.y, -state.second.x};
|
||||
if (map.Get(state.first + dir2) != '#')
|
||||
paths.emplace_back(1001, std::pair{state.first + dir2, dir2});
|
||||
|
||||
Index2D dir3 = Index2D{-state.second.y, state.second.x};
|
||||
if (map.Get(state.first + dir3) != '#')
|
||||
paths.emplace_back(1001, std::pair{state.first + dir3, dir3});
|
||||
|
||||
return paths;
|
||||
}
|
||||
|
||||
bool Goal(const Array2D<char>& map, const std::pair<Index2D, Index2D>& state)
|
||||
{
|
||||
return map.Get(state.first) == 'E';
|
||||
}
|
||||
|
||||
OUTPUT1(input)
|
||||
{
|
||||
return Helper::Dijkstras(input, std::pair{input.Find('S'), Index2D{1, 0}}, Branch, Goal);
|
||||
}
|
||||
|
||||
OUTPUT2(input)
|
||||
{
|
||||
std::set<std::pair<Index2D, Index2D>> allVisited =
|
||||
Helper::DijkstrasAllVisited(input, std::pair{input.Find('S'), Index2D{1, 0}}, Branch, Goal);
|
||||
|
||||
std::set<Index2D> solutions;
|
||||
for (const auto& [pos, dir] : allVisited) solutions.emplace(pos);
|
||||
|
||||
return solutions.size();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
#include <bitset>
|
||||
|
||||
#include "common/aoc.h"
|
||||
|
||||
namespace day17
|
||||
{
|
||||
struct Program
|
||||
{
|
||||
int64_t A;
|
||||
int64_t B;
|
||||
int64_t C;
|
||||
std::vector<int> instructions;
|
||||
};
|
||||
|
||||
REGISTER_DAY(2024, Day17, Program, int64_t);
|
||||
|
||||
REGISTER_TEST_EXAMPLE(2024, Day17, ExampleInput, 1, 0);
|
||||
REGISTER_TEST(2024, Day17, Input, 1, 0);
|
||||
REGISTER_TEST_EXAMPLE(2024, Day17, ExampleInput, 2, 117440);
|
||||
REGISTER_TEST(2024, Day17, Input, 2, 202322348616234);
|
||||
|
||||
READ_INPUT(input)
|
||||
{
|
||||
Program program;
|
||||
|
||||
std::string str;
|
||||
std::getline(input, str);
|
||||
std::stringstream ss{str};
|
||||
ss >> "Register A: " >> program.A;
|
||||
|
||||
std::getline(input, str);
|
||||
ss = std::stringstream{str};
|
||||
ss >> "Register B: " >> program.B;
|
||||
|
||||
std::getline(input, str);
|
||||
ss = std::stringstream{str};
|
||||
ss >> "Register C: " >> program.C;
|
||||
|
||||
std::getline(input, str);
|
||||
std::getline(input, str, ' ');
|
||||
program.instructions = Input::ReadInts(input, ',');
|
||||
|
||||
return program;
|
||||
}
|
||||
|
||||
int64_t Combo(int i, int64_t a, int64_t b, int64_t c)
|
||||
{
|
||||
if (i <= 3)
|
||||
return i;
|
||||
if (i == 4)
|
||||
return a;
|
||||
if (i == 5)
|
||||
return b;
|
||||
if (i == 6)
|
||||
return c;
|
||||
|
||||
std::cerr << "Invalid combo: " << i << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::vector<int> RunProgram(const Program& program)
|
||||
{
|
||||
int64_t a = program.A;
|
||||
int64_t b = program.B;
|
||||
int64_t c = program.C;
|
||||
int pc = 0;
|
||||
std::vector<int> result;
|
||||
|
||||
while (pc < program.instructions.size())
|
||||
{
|
||||
int ins = program.instructions[pc];
|
||||
int arg = program.instructions[pc + 1];
|
||||
|
||||
if (ins == 0)
|
||||
a = a >> Combo(arg, a, b, c);
|
||||
else if (ins == 1)
|
||||
b = b ^ arg;
|
||||
else if (ins == 2)
|
||||
b = Combo(arg, a, b, c) % 8;
|
||||
else if (ins == 3 && a != 0)
|
||||
pc = arg - 2;
|
||||
else if (ins == 4)
|
||||
b = b ^ c;
|
||||
else if (ins == 5)
|
||||
result.emplace_back(Combo(arg, a, b, c) % 8);
|
||||
else if (ins == 6)
|
||||
b = a >> Combo(arg, a, b, c);
|
||||
else if (ins == 7)
|
||||
c = a >> Combo(arg, a, b, c);
|
||||
|
||||
pc += 2;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<int64_t> GetDiffPeriodicity(const std::vector<int64_t>& ints)
|
||||
{
|
||||
if (ints.empty())
|
||||
return {};
|
||||
|
||||
const int MIN_LOOP_COUNT = 3;
|
||||
if ((ints.size() - 1) % MIN_LOOP_COUNT != 0)
|
||||
return {};
|
||||
|
||||
std::vector<int64_t> diffs;
|
||||
for (int i = 0; i < ints.size() - 1; i++)
|
||||
{
|
||||
diffs.emplace_back(ints[i + 1] - ints[i]);
|
||||
}
|
||||
|
||||
int loopSize = ints.size() / MIN_LOOP_COUNT;
|
||||
for (int i = 0; i < MIN_LOOP_COUNT - 1; i++)
|
||||
{
|
||||
for (int j = 0; j < loopSize; j++)
|
||||
{
|
||||
if (diffs[i * loopSize + j] != diffs[i * loopSize + loopSize + j])
|
||||
{
|
||||
return {};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {diffs.begin(), diffs.begin() + loopSize};
|
||||
}
|
||||
|
||||
OUTPUT1(input)
|
||||
{
|
||||
std::vector<int> result = RunProgram(input);
|
||||
std::cout << result << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
OUTPUT2(input)
|
||||
{
|
||||
int64_t aRegister = 0;
|
||||
int currentDepth = 0;
|
||||
std::vector<int64_t> diffs{1};
|
||||
std::vector<int64_t> aRegisterSolution{};
|
||||
Program program = input;
|
||||
int offset = 0;
|
||||
while (true)
|
||||
{
|
||||
program.A = aRegister;
|
||||
std::vector<int> vec = RunProgram(program);
|
||||
|
||||
if (vec == input.instructions)
|
||||
{
|
||||
return aRegister;
|
||||
}
|
||||
|
||||
if (vec.size() > currentDepth && vec[currentDepth] == program.instructions[currentDepth])
|
||||
{
|
||||
aRegisterSolution.emplace_back(aRegister);
|
||||
}
|
||||
|
||||
std::vector<int64_t> loop = GetDiffPeriodicity(aRegisterSolution);
|
||||
if (!loop.empty())
|
||||
{
|
||||
aRegister = aRegisterSolution[0];
|
||||
diffs = loop;
|
||||
aRegisterSolution.clear();
|
||||
offset = 0;
|
||||
currentDepth++;
|
||||
}
|
||||
else
|
||||
{
|
||||
aRegister += diffs[offset % diffs.size()];
|
||||
offset++;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
#include "common/aoc.h"
|
||||
|
||||
namespace day18
|
||||
{
|
||||
using Memory = std::map<Index2D, int>;
|
||||
REGISTER_DAY(2024, Day18, Memory, int32_t);
|
||||
|
||||
REGISTER_TEST_EXAMPLE(2024, Day18, ExampleInput, 1, 22);
|
||||
REGISTER_TEST(2024, Day18, Input, 1, 304);
|
||||
REGISTER_TEST_EXAMPLE(2024, Day18, ExampleInput, 2, 20);
|
||||
REGISTER_TEST(2024, Day18, Input, 2, 2876);
|
||||
|
||||
READ_INPUT(input)
|
||||
{
|
||||
std::map<Index2D, int> memory;
|
||||
std::string str;
|
||||
int i = 0;
|
||||
while (std::getline(input, str))
|
||||
{
|
||||
Index2D index;
|
||||
std::stringstream ss{str};
|
||||
ss >> index.x >> "," >> index.y;
|
||||
memory.emplace(index, i);
|
||||
i++;
|
||||
}
|
||||
return memory;
|
||||
}
|
||||
|
||||
struct Map
|
||||
{
|
||||
const std::map<Index2D, int>& memory;
|
||||
int size;
|
||||
int time;
|
||||
};
|
||||
|
||||
std::vector<std::pair<int, Index2D>> Branch(const Map& map, const Index2D& current)
|
||||
{
|
||||
std::vector<std::pair<int, Index2D>> branch;
|
||||
for (auto& dir : Helper::GetNeighborDirections())
|
||||
{
|
||||
Index2D pos = current + dir;
|
||||
if (pos.x < 0 || pos.y < 0 || pos.x > map.size || pos.y > map.size)
|
||||
continue;
|
||||
auto it = map.memory.find(pos);
|
||||
if (it == map.memory.end() || it->second >= map.time)
|
||||
branch.emplace_back(1, pos);
|
||||
}
|
||||
return branch;
|
||||
}
|
||||
|
||||
bool Goal(const Map& map, const Index2D& current)
|
||||
{
|
||||
return current.x == map.size && current.y == map.size;
|
||||
}
|
||||
|
||||
bool ValidPath(const Map& map, int index)
|
||||
{
|
||||
Map cpy = map;
|
||||
cpy.time = index;
|
||||
return Helper::Dijkstras(cpy, Index2D{0, 0}, Branch, Goal) != 0;
|
||||
}
|
||||
|
||||
OUTPUT1(input)
|
||||
{
|
||||
int32_t sum = 0;
|
||||
int time = 1024;
|
||||
int size = 70;
|
||||
if (isExample)
|
||||
{
|
||||
size = 6;
|
||||
time = 12;
|
||||
}
|
||||
Map map{input, size, time};
|
||||
return Helper::Dijkstras(map, Index2D{0, 0}, Branch, Goal);
|
||||
}
|
||||
|
||||
OUTPUT2(input)
|
||||
{
|
||||
int size = 70;
|
||||
if (isExample)
|
||||
size = 6;
|
||||
|
||||
Map map{input, size, 0};
|
||||
int result = Helper::BinarySearch(map, 0, input.size(), ValidPath);
|
||||
for (auto& index : input)
|
||||
{
|
||||
if (index.second == result)
|
||||
{
|
||||
std::cout << index.first.x << "," << index.first.y << std::endl;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
#include "common/aoc.h"
|
||||
|
||||
namespace day19
|
||||
{
|
||||
struct Towels
|
||||
{
|
||||
std::vector<std::string> patterns;
|
||||
std::vector<std::string> towels;
|
||||
};
|
||||
|
||||
REGISTER_DAY(2024, Day19, Towels, int64_t);
|
||||
|
||||
REGISTER_TEST_EXAMPLE(2024, Day19, ExampleInput, 1, 6);
|
||||
REGISTER_TEST(2024, Day19, Input, 1, 353);
|
||||
REGISTER_TEST_EXAMPLE(2024, Day19, ExampleInput, 2, 16);
|
||||
REGISTER_TEST(2024, Day19, Input, 2, 880877787214477);
|
||||
|
||||
READ_INPUT(input)
|
||||
{
|
||||
Towels strings;
|
||||
std::string str;
|
||||
std::getline(input, str);
|
||||
std::stringstream ss{str};
|
||||
while (std::getline(ss, str, ','))
|
||||
{
|
||||
if (str.front() == ' ')
|
||||
str = str.substr(1);
|
||||
strings.patterns.emplace_back(str);
|
||||
}
|
||||
|
||||
std::getline(input, str);
|
||||
|
||||
while (std::getline(input, str))
|
||||
{
|
||||
strings.towels.emplace_back(str);
|
||||
}
|
||||
return strings;
|
||||
}
|
||||
|
||||
bool HasCombination(const std::string& towel,
|
||||
const std::vector<std::string>& patterns,
|
||||
int offset,
|
||||
std::set<int>& memoization)
|
||||
{
|
||||
if (offset == towel.size())
|
||||
return true;
|
||||
|
||||
if (memoization.count(offset) != 0)
|
||||
return false;
|
||||
|
||||
for (auto& other : patterns)
|
||||
{
|
||||
if (Helper::StartsWith(std::string_view(towel.c_str() + offset, towel.size() - offset), other))
|
||||
{
|
||||
if (HasCombination(towel, patterns, offset + other.size(), memoization))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
memoization.emplace(offset);
|
||||
return false;
|
||||
}
|
||||
|
||||
int64_t AmountOfCombinations(const std::string& towel,
|
||||
const std::vector<std::string>& patterns,
|
||||
int offset,
|
||||
std::map<int, int64_t>& memoization)
|
||||
{
|
||||
if (offset == towel.size())
|
||||
return 1;
|
||||
|
||||
auto it = memoization.find(offset);
|
||||
if (it != memoization.end())
|
||||
return it->second;
|
||||
|
||||
int64_t amount = 0;
|
||||
for (auto& other : patterns)
|
||||
{
|
||||
if (Helper::StartsWith(std::string_view(towel.c_str() + offset, towel.size() - offset), other))
|
||||
{
|
||||
amount += AmountOfCombinations(towel, patterns, offset + other.size(), memoization);
|
||||
}
|
||||
}
|
||||
memoization[offset] = amount;
|
||||
return amount;
|
||||
}
|
||||
|
||||
OUTPUT1(input)
|
||||
{
|
||||
int64_t sum = 0;
|
||||
|
||||
for (auto& towel : input.towels)
|
||||
{
|
||||
std::set<int> memoization;
|
||||
if (HasCombination(towel, input.patterns, 0, memoization))
|
||||
sum++;
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
OUTPUT2(input)
|
||||
{
|
||||
int64_t sum = 0;
|
||||
|
||||
for (auto& towel : input.towels)
|
||||
{
|
||||
std::map<int, int64_t> memoization;
|
||||
sum += AmountOfCombinations(towel, input.patterns, 0, memoization);
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
#include "common/aoc.h"
|
||||
|
||||
namespace day20
|
||||
{
|
||||
REGISTER_DAY(2024, Day20, Array2D<char>, int32_t);
|
||||
|
||||
REGISTER_TEST_EXAMPLE(2024, Day20, ExampleInput, 1, 1);
|
||||
REGISTER_TEST(2024, Day20, Input, 1, 1429);
|
||||
REGISTER_TEST_EXAMPLE(2024, Day20, ExampleInput, 2, 285);
|
||||
REGISTER_TEST(2024, Day20, Input, 2, 988931);
|
||||
|
||||
READ_INPUT(input)
|
||||
{
|
||||
return Input::ReadArray2D(input);
|
||||
}
|
||||
|
||||
// Single path DFS, assumes the path can never hit a dead end
|
||||
static std::pair<int, std::vector<Index2D>> DFS(const Array2D<char>& map, const Index2D& initial)
|
||||
{
|
||||
std::vector<Index2D> path;
|
||||
Index2D prev = Index2D{-1, -1};
|
||||
std::pair<int, Index2D> cur{0, initial};
|
||||
path.emplace_back(initial);
|
||||
|
||||
while (map[cur.second] != 'E')
|
||||
{
|
||||
for (auto dir : Helper::GetNeighborDirections())
|
||||
{
|
||||
Index2D pos = cur.second + dir;
|
||||
if (map.IsInside(pos))
|
||||
{
|
||||
if (pos != prev && map[pos] != '#')
|
||||
{
|
||||
prev = cur.second;
|
||||
cur.first++;
|
||||
cur.second = pos;
|
||||
path.emplace_back(pos);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return {cur.first, path};
|
||||
}
|
||||
|
||||
int Cheat(const Array2D<char>& map, int cheatTime, int diff)
|
||||
{
|
||||
int sum = 0;
|
||||
std::pair<int, std::vector<Index2D>> path = DFS(map, map.Find('S'));
|
||||
|
||||
std::vector<int> distanceToGoal(map.width * map.height, -1);
|
||||
for (int i = 0; i < path.second.size(); i++)
|
||||
{
|
||||
distanceToGoal[map.GetIndex(path.second[i])] = path.second.size() - i - 1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < path.second.size(); i++)
|
||||
{
|
||||
for (int y = -cheatTime; y <= cheatTime; y++)
|
||||
{
|
||||
int yAbs = std::abs(y);
|
||||
for (int x = -cheatTime + yAbs; x <= cheatTime - yAbs; x++)
|
||||
{
|
||||
int xAbs = std::abs(x);
|
||||
int cost = i + xAbs + yAbs;
|
||||
Index2D pos{path.second[i].x + x, path.second[i].y + y};
|
||||
if (map.IsInside(pos))
|
||||
{
|
||||
int index = map.GetIndex(pos);
|
||||
if (distanceToGoal[index] >= 0)
|
||||
{
|
||||
if (cost + distanceToGoal[index] <= path.first - diff)
|
||||
{
|
||||
sum++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
OUTPUT1(input)
|
||||
{
|
||||
return Cheat(input, 2, isExample ? 50 : 100);
|
||||
}
|
||||
|
||||
OUTPUT2(input)
|
||||
{
|
||||
return Cheat(input, 20, isExample ? 50 : 100);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,213 @@
|
||||
#include "common/aoc.h"
|
||||
|
||||
namespace day21
|
||||
{
|
||||
REGISTER_DAY(2024, Day21, std::vector<std::string>, int64_t);
|
||||
|
||||
REGISTER_TEST_EXAMPLE(2024, Day21, ExampleInput, 1, 126384);
|
||||
REGISTER_TEST(2024, Day21, Input, 1, 177814);
|
||||
REGISTER_TEST_EXAMPLE(2024, Day21, ExampleInput, 2, 154115708116294);
|
||||
REGISTER_TEST(2024, Day21, Input, 2, 220493992841852);
|
||||
|
||||
READ_INPUT(input)
|
||||
{
|
||||
return Input::ReadLines(input);
|
||||
}
|
||||
|
||||
Index2D KeyPadCoord(char c)
|
||||
{
|
||||
if (c == '7')
|
||||
return Index2D{0, 0};
|
||||
if (c == '8')
|
||||
return Index2D{1, 0};
|
||||
if (c == '9')
|
||||
return Index2D{2, 0};
|
||||
|
||||
if (c == '4')
|
||||
return Index2D{0, 1};
|
||||
if (c == '5')
|
||||
return Index2D{1, 1};
|
||||
if (c == '6')
|
||||
return Index2D{2, 1};
|
||||
|
||||
if (c == '1')
|
||||
return Index2D{0, 2};
|
||||
if (c == '2')
|
||||
return Index2D{1, 2};
|
||||
if (c == '3')
|
||||
return Index2D{2, 2};
|
||||
|
||||
if (c == '0')
|
||||
return Index2D{1, 3};
|
||||
if (c == 'A')
|
||||
return Index2D{2, 3};
|
||||
|
||||
abort();
|
||||
}
|
||||
|
||||
Index2D MovePadCoord(const Index2D& from, const Index2D& to)
|
||||
{
|
||||
if (from.x < to.x)
|
||||
return Index2D{2, 1};
|
||||
if (from.x > to.x)
|
||||
return Index2D{0, 1};
|
||||
if (from.y < to.y)
|
||||
return Index2D{1, 1};
|
||||
if (from.y > to.y)
|
||||
return Index2D{1, 0};
|
||||
|
||||
abort();
|
||||
}
|
||||
|
||||
bool IsSameDir(const Index2D& prev, const Index2D& cur, const Index2D& next)
|
||||
{
|
||||
Index2D diffA = cur - prev;
|
||||
Index2D diffB = next - cur;
|
||||
|
||||
if (diffA.x < 0 && diffB.x < 0)
|
||||
return true;
|
||||
if (diffA.x > 0 && diffB.x > 0)
|
||||
return true;
|
||||
if (diffA.y < 0 && diffB.y < 0)
|
||||
return true;
|
||||
if (diffA.y > 0 && diffB.y > 0)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<std::vector<Index2D>> PossiblePaths(const Index2D& from, const Index2D& to, bool keypad)
|
||||
{
|
||||
std::set<Index2D> visited;
|
||||
std::queue<std::vector<Index2D>> openPath;
|
||||
openPath.emplace(std::vector<Index2D>{from});
|
||||
std::vector<std::vector<Index2D>> paths;
|
||||
|
||||
while (!openPath.empty())
|
||||
{
|
||||
auto path = openPath.front();
|
||||
openPath.pop();
|
||||
visited.emplace(path.back());
|
||||
|
||||
if (path.back() == to)
|
||||
{
|
||||
paths.emplace_back(path);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const auto& dir : Helper::GetNeighborDirections())
|
||||
{
|
||||
Index2D newPos = path.back() + dir;
|
||||
bool keyPadCondition =
|
||||
keypad && newPos != Index2D{0, 3} && newPos.x >= 0 && newPos.x <= 2 && newPos.y >= 0 && newPos.y <= 3;
|
||||
bool movePadCondition =
|
||||
!keypad && newPos != Index2D{0, 0} && newPos.x >= 0 && newPos.x <= 2 && newPos.y >= 0 && newPos.y <= 1;
|
||||
if (visited.count(newPos) == 0 && (keyPadCondition || movePadCondition))
|
||||
{
|
||||
std::vector<Index2D> newPath = path;
|
||||
|
||||
if (path.size() == 1)
|
||||
newPath.emplace_back(newPos);
|
||||
else if (!IsSameDir(path[path.size() - 2], path.back(), newPos))
|
||||
newPath.emplace_back(newPos);
|
||||
else
|
||||
newPath.back() = newPos;
|
||||
|
||||
openPath.emplace(newPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
return paths;
|
||||
}
|
||||
|
||||
struct State
|
||||
{
|
||||
Index2D from;
|
||||
Index2D to;
|
||||
int depth;
|
||||
int64_t amount;
|
||||
|
||||
bool operator<(const State& other) const
|
||||
{
|
||||
if (from != other.from)
|
||||
return from < other.from;
|
||||
if (to != other.to)
|
||||
return to < other.to;
|
||||
if (depth != other.depth)
|
||||
return depth < other.depth;
|
||||
return amount < other.amount;
|
||||
}
|
||||
};
|
||||
|
||||
int64_t Move(int maxDepth,
|
||||
const Index2D& from,
|
||||
const Index2D& to,
|
||||
int depth,
|
||||
int64_t amount,
|
||||
std::map<State, int64_t>& memoization)
|
||||
{
|
||||
if (depth == maxDepth)
|
||||
return Helper::ManhattanDistance(to, from) + amount;
|
||||
|
||||
State state{from, to, depth, amount};
|
||||
auto it = memoization.find(state);
|
||||
if (it != memoization.end())
|
||||
return it->second;
|
||||
|
||||
std::vector<std::vector<Index2D>> paths = PossiblePaths(from, to, depth == 0);
|
||||
int64_t min = std::numeric_limits<int64_t>::max();
|
||||
for (const auto& path : paths)
|
||||
{
|
||||
Index2D moveFrom = Index2D{2, 0};
|
||||
int64_t sum = 0;
|
||||
for (int j = 0; j < path.size() - 1; j++)
|
||||
{
|
||||
Index2D moveTo = MovePadCoord(path[j], path[j + 1]);
|
||||
|
||||
int diff = Helper::ManhattanDistance(path[j], path[j + 1]);
|
||||
sum += Move(maxDepth, moveFrom, moveTo, depth + 1, diff, memoization);
|
||||
|
||||
moveFrom = moveTo;
|
||||
}
|
||||
|
||||
int diff = Helper::ManhattanDistance(path.back(), path.front());
|
||||
sum += Move(maxDepth, moveFrom, Index2D{2, 0}, depth + 1, amount, memoization);
|
||||
|
||||
min = std::min(sum, min);
|
||||
}
|
||||
|
||||
memoization[state] = min;
|
||||
return min;
|
||||
}
|
||||
|
||||
int64_t Solve(const std::vector<std::string>& input, int depth)
|
||||
{
|
||||
std::map<State, int64_t> memoization;
|
||||
int64_t sum = 0;
|
||||
for (int i = 0; i < input.size(); i++)
|
||||
{
|
||||
Index2D moveFrom = KeyPadCoord('A');
|
||||
int64_t codeSum = 0;
|
||||
for (auto c : input[i])
|
||||
{
|
||||
Index2D keyPadCoord = KeyPadCoord(c);
|
||||
codeSum += Move(depth, moveFrom, keyPadCoord, 0, 1, memoization);
|
||||
moveFrom = keyPadCoord;
|
||||
}
|
||||
int64_t codeNum = std::stoi(input[i]);
|
||||
sum += codeNum * codeSum;
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
OUTPUT1(input)
|
||||
{
|
||||
return Solve(input, 2);
|
||||
}
|
||||
|
||||
OUTPUT2(input)
|
||||
{
|
||||
return Solve(input, 25);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
#include "common/aoc.h"
|
||||
|
||||
namespace day22
|
||||
{
|
||||
REGISTER_DAY(2024, Day22, std::vector<int>, int64_t);
|
||||
|
||||
REGISTER_TEST_EXAMPLE(2024, Day22, ExampleInput, 1, 37990510);
|
||||
REGISTER_TEST(2024, Day22, Input, 1, 14273043166);
|
||||
REGISTER_TEST_EXAMPLE(2024, Day22, ExampleInput, 2, 23);
|
||||
REGISTER_TEST(2024, Day22, Input, 2, 1667);
|
||||
|
||||
READ_INPUT(input)
|
||||
{
|
||||
return Input::ReadInts(input);
|
||||
}
|
||||
|
||||
int64_t NextNumber(int64_t currentNum)
|
||||
{
|
||||
currentNum = ((currentNum * 64) ^ currentNum) % 16777216;
|
||||
currentNum = ((currentNum / 32) ^ currentNum) % 16777216;
|
||||
currentNum = ((currentNum * 2048) ^ currentNum) % 16777216;
|
||||
return currentNum;
|
||||
}
|
||||
|
||||
int GetDiffIndex(const std::vector<int>& vec)
|
||||
{
|
||||
int val = 0;
|
||||
for (int i = vec.size() - 5; i < vec.size() - 1; i++)
|
||||
{
|
||||
val *= 19;
|
||||
val += vec[i + 1] - vec[i] + 9;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
OUTPUT1(input)
|
||||
{
|
||||
int64_t sum = 0;
|
||||
for (auto num : input)
|
||||
{
|
||||
for (int i = 0; i < 2000; i++)
|
||||
{
|
||||
num = NextNumber(num);
|
||||
}
|
||||
sum += num;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
OUTPUT2(input)
|
||||
{
|
||||
const int MAX_INDEX = 19 * 19 * 19 * 19;
|
||||
std::vector<int> monkeySequences(MAX_INDEX, 0);
|
||||
int best = 0;
|
||||
for (auto num : input)
|
||||
{
|
||||
std::vector<bool> alreadyFoundSequence(MAX_INDEX, false);
|
||||
std::vector<int> sequence;
|
||||
sequence.emplace_back(num % 10);
|
||||
for (int i = 0; i < 2000; i++)
|
||||
{
|
||||
num = NextNumber(num);
|
||||
sequence.emplace_back(num % 10);
|
||||
if (sequence.size() >= 5)
|
||||
{
|
||||
int diffIndex = GetDiffIndex(sequence);
|
||||
if (!alreadyFoundSequence[diffIndex])
|
||||
{
|
||||
alreadyFoundSequence[diffIndex] = true;
|
||||
monkeySequences[diffIndex] += num % 10;
|
||||
if (monkeySequences[diffIndex] > best)
|
||||
best = monkeySequences[diffIndex];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return best;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
#include "common/aoc.h"
|
||||
|
||||
namespace day23
|
||||
{
|
||||
struct Network
|
||||
{
|
||||
std::map<std::string, std::set<std::string>> graph;
|
||||
};
|
||||
|
||||
REGISTER_DAY(2024, Day23, Network, int64_t);
|
||||
|
||||
REGISTER_TEST_EXAMPLE(2024, Day23, ExampleInput, 1, 7);
|
||||
REGISTER_TEST(2024, Day23, Input, 1, 1170);
|
||||
REGISTER_TEST_EXAMPLE(2024, Day23, ExampleInput, 2, 52);
|
||||
REGISTER_TEST(2024, Day23, Input, 2, 350);
|
||||
|
||||
READ_INPUT(input)
|
||||
{
|
||||
Network network;
|
||||
std::string str;
|
||||
while (std::getline(input, str))
|
||||
{
|
||||
std::stringstream ss{str};
|
||||
std::string s1, s2;
|
||||
std::getline(ss, s1, '-');
|
||||
std::getline(ss, s2, '-');
|
||||
network.graph[s1].emplace(s2);
|
||||
network.graph[s2].emplace(s1);
|
||||
}
|
||||
return network;
|
||||
}
|
||||
|
||||
void FindLargest(const Network& network, std::set<std::string>& computers, std::set<std::string>& largest)
|
||||
{
|
||||
if (computers.size() <= largest.size())
|
||||
return;
|
||||
|
||||
for (const auto& computer : computers)
|
||||
{
|
||||
for (const auto& otherComputer : computers)
|
||||
{
|
||||
if (otherComputer == computer)
|
||||
continue;
|
||||
|
||||
const auto& neighbors = network.graph.find(computer)->second;
|
||||
if (neighbors.find(otherComputer) == neighbors.end())
|
||||
{
|
||||
// Solution wasn't found, so remove an element and try for a smaller set of computers
|
||||
for (const auto& node : computers)
|
||||
{
|
||||
auto cpy = computers;
|
||||
cpy.erase(node);
|
||||
FindLargest(network, cpy, largest);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
largest = computers;
|
||||
}
|
||||
|
||||
OUTPUT1(input)
|
||||
{
|
||||
std::set<std::set<std::string>> groupsOfThree;
|
||||
for (const auto& computer : input.graph)
|
||||
{
|
||||
if (computer.first[0] != 't')
|
||||
continue;
|
||||
|
||||
for (auto it = computer.second.begin(); it != computer.second.end(); it++)
|
||||
{
|
||||
auto it2 = it;
|
||||
it2++;
|
||||
for (it2; it2 != computer.second.end(); it2++)
|
||||
{
|
||||
const auto& paths = input.graph.find(*it)->second;
|
||||
if (paths.find(*it2) != paths.end())
|
||||
groupsOfThree.emplace(std::set<std::string>{computer.first, *it, *it2});
|
||||
}
|
||||
}
|
||||
}
|
||||
return groupsOfThree.size();
|
||||
}
|
||||
|
||||
OUTPUT2(input)
|
||||
{
|
||||
std::set<std::string> largest;
|
||||
for (const auto& computer : input.graph)
|
||||
{
|
||||
std::set<std::string> computers = computer.second;
|
||||
computers.emplace(computer.first);
|
||||
FindLargest(input, computers, largest);
|
||||
}
|
||||
|
||||
for (const auto& s : largest) std::cout << s << ",";
|
||||
std::cout << std::endl;
|
||||
|
||||
// Some arbitrary solution number to have some form of verification in the code.
|
||||
// Sum all letters of the computers (with a=0, b=1, etc)
|
||||
int64_t sum = 0;
|
||||
for (const auto& s : largest) sum += (s[0] - 'a') + (s[1] - 'a');
|
||||
|
||||
return sum;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,233 @@
|
||||
#include "common/aoc.h"
|
||||
|
||||
namespace day24
|
||||
{
|
||||
struct Gate
|
||||
{
|
||||
std::string left;
|
||||
std::string right;
|
||||
std::string op;
|
||||
std::string res;
|
||||
};
|
||||
|
||||
struct Gates
|
||||
{
|
||||
std::map<std::string, int> gates;
|
||||
std::vector<Gate> gateOperation;
|
||||
};
|
||||
|
||||
REGISTER_DAY(2024, Day24, Gates, int64_t);
|
||||
|
||||
REGISTER_TEST_EXAMPLE(2024, Day24, ExampleInput, 1, 2024);
|
||||
REGISTER_TEST(2024, Day24, Input, 1, 57344080719736);
|
||||
// REGISTER_TEST_EXAMPLE(2024, Day24, ExampleInput, 2, 0);
|
||||
REGISTER_TEST(2024, Day24, Input, 2, 2328);
|
||||
|
||||
READ_INPUT(input)
|
||||
{
|
||||
std::string str;
|
||||
Gates gates;
|
||||
while (std::getline(input, str))
|
||||
{
|
||||
if (str.empty())
|
||||
break;
|
||||
std::stringstream ss{str};
|
||||
std::string name;
|
||||
int val;
|
||||
ss >> name >> val;
|
||||
name.pop_back(); // Remove ':'
|
||||
gates.gates.emplace(name, val);
|
||||
}
|
||||
|
||||
while (std::getline(input, str))
|
||||
{
|
||||
std::stringstream ss{str};
|
||||
std::string left;
|
||||
std::string right;
|
||||
std::string op;
|
||||
std::string res;
|
||||
ss >> left >> op >> right >> "->" >> res;
|
||||
|
||||
Gate gate{left, right, op, res};
|
||||
gates.gates.emplace(res, -1);
|
||||
gates.gateOperation.emplace_back(gate);
|
||||
}
|
||||
return gates;
|
||||
}
|
||||
|
||||
int GetVal(Gates& gates, const std::string& wire)
|
||||
{
|
||||
return gates.gates[wire];
|
||||
}
|
||||
|
||||
void SetVal(Gates& gates, const std::string& wire, int val)
|
||||
{
|
||||
gates.gates[wire] = val;
|
||||
}
|
||||
|
||||
void SetInput(Gates& gates, int64_t x, int64_t y)
|
||||
{
|
||||
for (auto& wire : gates.gates)
|
||||
{
|
||||
if (wire.first[0] == 'x')
|
||||
{
|
||||
wire.second = x & 1;
|
||||
x >>= 1;
|
||||
}
|
||||
if (wire.first[0] == 'y')
|
||||
{
|
||||
wire.second = y & 1;
|
||||
y >>= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string IndexToStr(int i)
|
||||
{
|
||||
std::string s;
|
||||
if (i < 10)
|
||||
s += "0";
|
||||
s += std::to_string(i);
|
||||
return s;
|
||||
}
|
||||
|
||||
void SwapOutputs(Gates& gates, const std::string& output1, const std::string& output2, std::set<std::string>& swapped)
|
||||
{
|
||||
int i1 = -1;
|
||||
int i2 = -1;
|
||||
for (int i = 0; i < gates.gateOperation.size(); i++)
|
||||
{
|
||||
if (gates.gateOperation[i].res == output1)
|
||||
i1 = i;
|
||||
if (gates.gateOperation[i].res == output2)
|
||||
i2 = i;
|
||||
}
|
||||
|
||||
std::swap(gates.gateOperation[i1].res, gates.gateOperation[i2].res);
|
||||
swapped.emplace(gates.gateOperation[i1].res);
|
||||
swapped.emplace(gates.gateOperation[i2].res);
|
||||
}
|
||||
|
||||
std::string Find(const Gates& gates, const std::string& left, const std::string& right, const std::string& op)
|
||||
{
|
||||
for (const auto& gate : gates.gateOperation)
|
||||
{
|
||||
if (gate.op == op)
|
||||
{
|
||||
if ((gate.left == left && gate.right == right) || (gate.left == right && gate.right == left))
|
||||
{
|
||||
return gate.res;
|
||||
}
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
OUTPUT1(input)
|
||||
{
|
||||
// Too low: 1972354943
|
||||
Gates cpy = input;
|
||||
bool somethingChanged = true;
|
||||
while (somethingChanged)
|
||||
{
|
||||
somethingChanged = false;
|
||||
for (const auto& gate : cpy.gateOperation)
|
||||
{
|
||||
int leftVal = GetVal(cpy, gate.left);
|
||||
int rightVal = GetVal(cpy, gate.right);
|
||||
if (leftVal != -1 && rightVal != -1 && GetVal(cpy, gate.res) == -1)
|
||||
{
|
||||
somethingChanged = true;
|
||||
if (gate.op == "AND")
|
||||
{
|
||||
SetVal(cpy, gate.res, leftVal & rightVal);
|
||||
}
|
||||
else if (gate.op == "OR")
|
||||
{
|
||||
SetVal(cpy, gate.res, leftVal | rightVal);
|
||||
}
|
||||
else if (gate.op == "XOR")
|
||||
{
|
||||
SetVal(cpy, gate.res, leftVal ^ rightVal);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int64_t num = 0;
|
||||
for (const auto& wire : cpy.gates)
|
||||
{
|
||||
if (wire.first[0] == 'z')
|
||||
{
|
||||
int pos = std::stoi(wire.first.substr(1));
|
||||
num |= ((int64_t)wire.second << pos);
|
||||
}
|
||||
}
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
OUTPUT2(input)
|
||||
{
|
||||
Gates gates = input;
|
||||
std::set<std::string> outputs;
|
||||
for (const auto& gate : gates.gateOperation)
|
||||
{
|
||||
outputs.emplace(gate.res);
|
||||
}
|
||||
|
||||
std::string carry{Find(gates, "x00", "y00", "AND")};
|
||||
|
||||
std::set<std::string> swapped;
|
||||
for (int i = 1; i < 46; i++)
|
||||
{
|
||||
std::string index = IndexToStr(i);
|
||||
std::string x = "x" + index;
|
||||
std::string y = "y" + index;
|
||||
std::string z = "z" + index;
|
||||
|
||||
std::string xorIn = Find(gates, x, y, "XOR");
|
||||
std::string res = Find(gates, carry, xorIn, "XOR");
|
||||
if (res.empty())
|
||||
{
|
||||
for (const auto& output : outputs)
|
||||
{
|
||||
std::string res = Find(gates, carry, output, "XOR");
|
||||
if (res == z)
|
||||
{
|
||||
SwapOutputs(gates, xorIn, output, swapped);
|
||||
xorIn = output;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (res != z)
|
||||
{
|
||||
SwapOutputs(gates, res, z, swapped);
|
||||
}
|
||||
|
||||
std::string andIn = Find(gates, x, y, "AND");
|
||||
std::string andXorInCarry = Find(gates, xorIn, carry, "AND");
|
||||
carry = Find(gates, andIn, andXorInCarry, "OR");
|
||||
}
|
||||
|
||||
for (const auto& swap : swapped)
|
||||
{
|
||||
std::cout << swap << ",";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
|
||||
// Some arbitrary solution number to have some form of verification in the code.
|
||||
// Sum all letters in the swapped outputs
|
||||
int64_t sum = 0;
|
||||
for (const auto& s : swapped)
|
||||
{
|
||||
for (char c : s)
|
||||
{
|
||||
sum += c = 'a';
|
||||
}
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
#include "common/aoc.h"
|
||||
|
||||
namespace day25
|
||||
{
|
||||
struct KeysLocks
|
||||
{
|
||||
int height{0};
|
||||
std::vector<std::vector<int>> keys;
|
||||
std::vector<std::vector<int>> locks;
|
||||
};
|
||||
|
||||
REGISTER_DAY(2024, Day25, KeysLocks, int);
|
||||
|
||||
REGISTER_TEST_EXAMPLE(2024, Day25, ExampleInput, 1, 3);
|
||||
REGISTER_TEST(2024, Day25, Input, 1, 3663);
|
||||
REGISTER_TEST_EXAMPLE(2024, Day25, ExampleInput, 2, 0);
|
||||
REGISTER_TEST(2024, Day25, Input, 2, 0);
|
||||
|
||||
READ_INPUT(input)
|
||||
{
|
||||
KeysLocks keysLocks;
|
||||
|
||||
bool next = true;
|
||||
while (next)
|
||||
{
|
||||
next = false;
|
||||
std::string str;
|
||||
std::vector<int> lockOrKey;
|
||||
bool lock = true;
|
||||
int height = 0;
|
||||
while (std::getline(input, str))
|
||||
{
|
||||
next = true;
|
||||
if (str.empty())
|
||||
break;
|
||||
|
||||
if (lockOrKey.empty())
|
||||
{
|
||||
if (str[0] == '.')
|
||||
lock = false;
|
||||
|
||||
lockOrKey = std::vector<int>(str.size(), 0);
|
||||
}
|
||||
|
||||
for (int i = 0; i < str.size(); i++)
|
||||
{
|
||||
if (str[i] == '#')
|
||||
lockOrKey[i]++;
|
||||
}
|
||||
height++;
|
||||
}
|
||||
|
||||
if (keysLocks.height == 0)
|
||||
keysLocks.height = height;
|
||||
|
||||
if (!lockOrKey.empty())
|
||||
{
|
||||
if (lock)
|
||||
keysLocks.locks.emplace_back(lockOrKey);
|
||||
else
|
||||
keysLocks.keys.emplace_back(lockOrKey);
|
||||
}
|
||||
}
|
||||
|
||||
return keysLocks;
|
||||
}
|
||||
|
||||
OUTPUT1(input)
|
||||
{
|
||||
int64_t sum = 0;
|
||||
for (const auto& key : input.keys)
|
||||
{
|
||||
for (const auto& lock : input.locks)
|
||||
{
|
||||
bool matches = true;
|
||||
for (int i = 0; i < key.size(); i++)
|
||||
{
|
||||
if (key[i] + lock[i] > input.height)
|
||||
{
|
||||
matches = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (matches)
|
||||
sum++;
|
||||
}
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
OUTPUT2(input)
|
||||
{
|
||||
std::cout << " ___ ___" << std::endl;
|
||||
std::cout << " (o o) (o o)" << std::endl;
|
||||
std::cout << "( V ) MERRY CHRISTMAS! ( V )" << std::endl;
|
||||
std::cout << "--m-m----------------------m-m--" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user