Day5
This commit is contained in:
parent
840f236c60
commit
43448aaeb6
9 changed files with 1434 additions and 89 deletions
|
|
@ -13,8 +13,20 @@ RUN apt-get update \
|
||||||
python3 \
|
python3 \
|
||||||
python3-pip \
|
python3-pip \
|
||||||
ca-certificates \
|
ca-certificates \
|
||||||
|
curl \
|
||||||
|
wget \
|
||||||
|
tmux \
|
||||||
|
ripgrep \
|
||||||
|
fd-find \
|
||||||
|
unzip \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
RUN curl -LO https://github.com/neovim/neovim/releases/download/stable/nvim-linux-x86_64.tar.gz \
|
||||||
|
&& rm -rf /opt/nvim \
|
||||||
|
&& tar -C /opt -xzf nvim-linux-x86_64.tar.gz \
|
||||||
|
&& ln -sf /opt/nvim-linux-x86_64/bin/nvim /usr/local/bin/nvim \
|
||||||
|
&& rm nvim-linux-x86_64.tar.gz
|
||||||
|
|
||||||
# Create workspace folder (VS Code devcontainer convention)
|
# Create workspace folder (VS Code devcontainer convention)
|
||||||
ARG WORKSPACE_FOLDER=/workspaces/aoc25
|
ARG WORKSPACE_FOLDER=/workspaces/aoc25
|
||||||
RUN mkdir -p ${WORKSPACE_FOLDER} && chown -R root:root ${WORKSPACE_FOLDER}
|
RUN mkdir -p ${WORKSPACE_FOLDER} && chown -R root:root ${WORKSPACE_FOLDER}
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
"ms-vscode.cpptools",
|
"ms-vscode.cpptools",
|
||||||
"ms-vscode.cmake-tools",
|
"ms-vscode.cmake-tools",
|
||||||
"llvm-vs-code-extensions.vscode-clangd",
|
"llvm-vs-code-extensions.vscode-clangd",
|
||||||
"xaver.clang-format"
|
"vadimcn.vscode-lldb"
|
||||||
],
|
],
|
||||||
"postCreateCommand": "cmake -S . -B build || true"
|
"postCreateCommand": "cmake -S . -B build || true"
|
||||||
}
|
}
|
||||||
|
|
@ -38,4 +38,5 @@ add_subdirectory(day1)
|
||||||
add_subdirectory(day2)
|
add_subdirectory(day2)
|
||||||
add_subdirectory(day3)
|
add_subdirectory(day3)
|
||||||
add_subdirectory(day4)
|
add_subdirectory(day4)
|
||||||
|
add_subdirectory(day5)
|
||||||
|
|
||||||
|
|
|
||||||
160
day2/main.cpp
160
day2/main.cpp
|
|
@ -1,35 +1,32 @@
|
||||||
#include <iostream>
|
#include <algorithm>
|
||||||
#include <fstream>
|
|
||||||
#include <string>
|
|
||||||
#include <string_view>
|
|
||||||
#include <vector>
|
|
||||||
#include <expected>
|
#include <expected>
|
||||||
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
#include <print>
|
#include <print>
|
||||||
#include <ranges>
|
#include <ranges>
|
||||||
#include <array>
|
#include <string>
|
||||||
#include <map>
|
#include <string_view>
|
||||||
#include <numeric>
|
#include <unordered_map>
|
||||||
#include <functional>
|
#include <vector>
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
struct IDRange {
|
struct IDRange {
|
||||||
long leftRange;
|
long leftRange;
|
||||||
long rightRange;
|
long rightRange;
|
||||||
};
|
};
|
||||||
|
|
||||||
auto parseRanges(const std::string& filename) -> std::expected<std::vector<IDRange>, std::string> {
|
auto parseRanges(const std::string &filename) -> std::expected<std::vector<IDRange>, std::string> {
|
||||||
std::ifstream inputF {filename};
|
std::ifstream inputF{filename};
|
||||||
|
|
||||||
if (!inputF){
|
if (!inputF) {
|
||||||
return std::unexpected{"Some file open error.\n"};
|
return std::unexpected{"Some file open error.\n"};
|
||||||
}
|
}
|
||||||
std::vector<IDRange> idRanges{};
|
std::vector<IDRange> idRanges{};
|
||||||
|
|
||||||
std::string bigString{};
|
std::string bigString{};
|
||||||
std::getline(inputF,bigString);
|
std::getline(inputF, bigString);
|
||||||
auto ranges = std::ranges::to<std::vector<std::string>>(std::views::split(bigString, ','));
|
auto ranges = std::ranges::to<std::vector<std::string>>(std::views::split(bigString, ','));
|
||||||
|
|
||||||
for(const auto& range : ranges){
|
for (const auto &range : ranges) {
|
||||||
auto subParts = std::ranges::to<std::vector<std::string>>(std::views::split(range, '-'));
|
auto subParts = std::ranges::to<std::vector<std::string>>(std::views::split(range, '-'));
|
||||||
idRanges.emplace_back(std::stol(subParts[0]), std::stol(subParts[1]));
|
idRanges.emplace_back(std::stol(subParts[0]), std::stol(subParts[1]));
|
||||||
}
|
}
|
||||||
|
|
@ -39,115 +36,106 @@ auto parseRanges(const std::string& filename) -> std::expected<std::vector<IDRan
|
||||||
return std::move(idRanges);
|
return std::move(idRanges);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto countDoubles(const std::vector<IDRange> &idRanges) {
|
||||||
auto countDoubles(const std::vector<IDRange>& idRanges) {
|
|
||||||
long doubles{};
|
long doubles{};
|
||||||
for(const auto& rng : idRanges){
|
for (const auto &rng : idRanges) {
|
||||||
//std::println("{}-{}", rng.leftRange, rng.rightRange);
|
// std::println("{}-{}", rng.leftRange, rng.rightRange);
|
||||||
for( long i = rng.leftRange; i <= rng.rightRange; i++){
|
for (long i = rng.leftRange; i <= rng.rightRange; i++) {
|
||||||
auto str_version = std::to_string(i) ;
|
auto str_version = std::to_string(i);
|
||||||
auto str_len = str_version.size();
|
auto str_len = str_version.size();
|
||||||
//std::print("Checking {}. Length: {}", str_version, str_version.size());
|
// std::print("Checking {}. Length: {}", str_version, str_version.size());
|
||||||
if (str_len % 2 == 0) {
|
if (str_len % 2 == 0) {
|
||||||
//std::print(" Divisible by two, splitting...");
|
// std::print(" Divisible by two, splitting...");
|
||||||
std::string_view left_half = std::string_view(str_version).substr(0, str_len/2);
|
std::string_view left_half = std::string_view(str_version).substr(0, str_len / 2);
|
||||||
std::string_view right_half = std::string_view(str_version).substr(str_len/2, str_len);
|
std::string_view right_half = std::string_view(str_version).substr(str_len / 2, str_len);
|
||||||
//std::print("Halves: {}/{}",left_half, right_half);
|
// std::print("Halves: {}/{}",left_half, right_half);
|
||||||
if(left_half == right_half){
|
if (left_half == right_half) {
|
||||||
//std::print(" EQUAL!");
|
// std::print(" EQUAL!");
|
||||||
doubles += i;
|
doubles += i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//std::println();
|
// std::println();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return doubles;
|
return doubles;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto calculatePossibleSplits(int length) -> std::vector<int> {
|
||||||
|
// std::println("Possible ways to split a str of length {}: ", length);
|
||||||
auto calculatePossibleSplits(int length) -> std::vector<int>{
|
|
||||||
//std::println("Possible ways to split a str of length {}: ", length);
|
|
||||||
std::vector<int> returnVec{};
|
std::vector<int> returnVec{};
|
||||||
for(auto toCheck : std::views::iota(2, length+1)){
|
for (auto toCheck : std::views::iota(2, length + 1)) {
|
||||||
if(length % toCheck == 0)
|
if (length % toCheck == 0) {
|
||||||
{
|
// std::println("{}", toCheck);
|
||||||
//std::println("{}", toCheck);
|
|
||||||
returnVec.push_back(toCheck);
|
returnVec.push_back(toCheck);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return std::move(returnVec);
|
return std::move(returnVec);
|
||||||
}
|
}
|
||||||
std::unordered_map<int, std::vector<int>> splitMap{};
|
std::unordered_map<int, std::vector<int>> splitMap{};
|
||||||
auto getPossibleSplits(int length) -> const std::vector<int>&{
|
auto getPossibleSplits(int length) -> const std::vector<int> & {
|
||||||
if(!splitMap.contains(length)){
|
if (!splitMap.contains(length)) {
|
||||||
//std::println("Caching {}",length);
|
// std::println("Caching {}",length);
|
||||||
splitMap[length] = calculatePossibleSplits(length);
|
splitMap[length] = calculatePossibleSplits(length);
|
||||||
}
|
}
|
||||||
return splitMap.at(length);
|
return splitMap.at(length);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto countRepeats(const std::vector<IDRange>& idRanges) {
|
auto countRepeats(const std::vector<IDRange> &idRanges) {
|
||||||
long doubles{};
|
long doubles{};
|
||||||
for(const auto& rng : idRanges){
|
for (const auto &rng : idRanges) {
|
||||||
//std::println("{}-{}", rng.leftRange, rng.rightRange);
|
// std::println("{}-{}", rng.leftRange, rng.rightRange);
|
||||||
for( long i = rng.leftRange; i <= rng.rightRange; i++){
|
for (long i = rng.leftRange; i <= rng.rightRange; i++) {
|
||||||
auto str_version = std::to_string(i) ;
|
auto str_version = std::to_string(i);
|
||||||
auto str_len = str_version.size();
|
auto str_len = str_version.size();
|
||||||
//std::print("Checking {}. Length: {} ", str_version, str_version.size());
|
// std::print("Checking {}. Length: {} ", str_version, str_version.size());
|
||||||
|
|
||||||
std::vector<int> numsToCheck = getPossibleSplits(str_len);
|
const std::vector<int> &numsToCheck = getPossibleSplits(str_len);
|
||||||
//std::println("Possible splits: {}", numsToCheck);
|
// std::println("Possible splits: {}", numsToCheck);
|
||||||
for (int checkNum : numsToCheck)
|
for (int checkNum : numsToCheck) {
|
||||||
{
|
// std::print("Splitting in {}: ", checkNum);
|
||||||
//std::print("Splitting in {}: ", checkNum);
|
std::vector<std::string_view> splits(checkNum);
|
||||||
std::vector<std::string_view> splits(checkNum);
|
for (auto toCheck : std::views::iota(0, checkNum)) {
|
||||||
for(auto toCheck : std::views::iota(0, checkNum)){
|
auto window = str_len / checkNum;
|
||||||
auto window = str_len/checkNum;
|
splits[toCheck] = std::string_view(str_version).substr(toCheck * window, window);
|
||||||
splits[toCheck] = std::string_view(str_version).substr(toCheck*window, window);
|
// std::print("[{}]: {} /{} ", toCheck, splits[toCheck], window);
|
||||||
//std::print("[{}]: {} /{} ", toCheck, splits[toCheck], window);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(std::equal(splits.begin() + 1, splits.end(), splits.begin())){
|
if (std::equal(splits.begin() + 1, splits.end(), splits.begin())) {
|
||||||
//std::print(" EQUAL!");
|
// std::print(" EQUAL!");
|
||||||
doubles += i;
|
doubles += i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
//std::println();
|
// std::println();
|
||||||
}
|
}
|
||||||
//std::println();
|
// std::println();
|
||||||
}
|
}
|
||||||
//std::println();
|
// std::println();
|
||||||
}
|
}
|
||||||
return doubles;
|
return doubles;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto main() -> int {
|
auto main() -> int {
|
||||||
|
|
||||||
|
|
||||||
auto testCase = parseRanges("test_input");
|
auto testCase = parseRanges("test_input");
|
||||||
if(testCase) {
|
if (testCase) {
|
||||||
auto testResult = countDoubles(*testCase);
|
auto testResult = countDoubles(*testCase);
|
||||||
auto testResultP2 = countRepeats(*testCase);
|
auto testResultP2 = countRepeats(*testCase);
|
||||||
std::println("P1 Testcase result: {}", testResult);
|
std::println("P1 Testcase result: {}", testResult);
|
||||||
std::println("P2 Testcase result: {}", testResultP2);
|
std::println("P2 Testcase result: {}", testResultP2);
|
||||||
|
} else {
|
||||||
|
std::print("{}\n", testCase.error());
|
||||||
}
|
}
|
||||||
else{
|
|
||||||
std::print("{}\n", testCase.error());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
auto realRanges = parseRanges("puzzle_input");
|
auto realRanges = parseRanges("puzzle_input");
|
||||||
if(realRanges) {
|
if (realRanges) {
|
||||||
//auto realResult = countDoubles(*realRanges);
|
// auto realResult = countDoubles(*realRanges);
|
||||||
auto realResultP2 = countRepeats(*realRanges);
|
auto realResultP2 = countRepeats(*realRanges);
|
||||||
//std::println("P1 Real result: {}", realResult);
|
// std::println("P1 Real result: {}", realResult);
|
||||||
std::println("P2 Real result: {}", realResultP2);
|
std::println("P2 Real result: {}", realResultP2);
|
||||||
|
} else {
|
||||||
|
std::print("{}\n", realRanges.error());
|
||||||
}
|
}
|
||||||
else{
|
|
||||||
std::print("{}\n", realRanges.error());
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,6 @@ struct Diagram {
|
||||||
auto grid() { return GridView(data.data(), height, width); }
|
auto grid() { return GridView(data.data(), height, width); }
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace {
|
|
||||||
auto printMap(Diagram &diagram) {
|
auto printMap(Diagram &diagram) {
|
||||||
auto grid = diagram.grid();
|
auto grid = diagram.grid();
|
||||||
for (auto row = 0UZ; row != grid.extent(0); row++) {
|
for (auto row = 0UZ; row != grid.extent(0); row++) {
|
||||||
|
|
@ -137,7 +136,7 @@ auto moveMoveablePaper(Diagram &diagram) -> long {
|
||||||
|
|
||||||
return totalPaperRemoved;
|
return totalPaperRemoved;
|
||||||
}
|
}
|
||||||
} // namespace
|
|
||||||
auto main() -> int {
|
auto main() -> int {
|
||||||
auto testCase = parseMap("test_input");
|
auto testCase = parseMap("test_input");
|
||||||
if (testCase) {
|
if (testCase) {
|
||||||
|
|
|
||||||
2
day5/CMakeLists.txt
Normal file
2
day5/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
# Use top-level helper to add the target and copy input files
|
||||||
|
aoc_add_day(day5 "${CMAKE_CURRENT_SOURCE_DIR}" main.cpp)
|
||||||
144
day5/main.cpp
Normal file
144
day5/main.cpp
Normal file
|
|
@ -0,0 +1,144 @@
|
||||||
|
#include <algorithm>
|
||||||
|
#include <array>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <expected>
|
||||||
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
#include <list>
|
||||||
|
#include <mdspan>
|
||||||
|
#include <print>
|
||||||
|
#include <ranges>
|
||||||
|
#include <set>
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_set>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
// struct FreshRange {
|
||||||
|
// long long left;
|
||||||
|
// long long right;
|
||||||
|
// };
|
||||||
|
|
||||||
|
using FreshRange = std::pair<long long, long long>;
|
||||||
|
|
||||||
|
struct PuzzleInput {
|
||||||
|
std::vector<FreshRange> freshRanges;
|
||||||
|
std::vector<long long> ingredients;
|
||||||
|
};
|
||||||
|
|
||||||
|
static auto parseInput(const std::string &filename) -> std::expected<PuzzleInput, std::string> {
|
||||||
|
std::ifstream inputF{filename};
|
||||||
|
|
||||||
|
if (!inputF) {
|
||||||
|
return std::unexpected{"Some file open error.\n"};
|
||||||
|
}
|
||||||
|
PuzzleInput puzzleInput{};
|
||||||
|
|
||||||
|
std::string puzzleLine{};
|
||||||
|
while (std::getline(inputF, puzzleLine)) {
|
||||||
|
if (puzzleLine.empty()) {
|
||||||
|
std::println("Empty string");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
auto subParts = std::ranges::to<std::vector<std::string>>(std::views::split(puzzleLine, '-'));
|
||||||
|
puzzleInput.freshRanges.emplace_back(std::stoll(subParts[0]), std::stoll(subParts[1]));
|
||||||
|
std::println("Range: {}", subParts);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (std::getline(inputF, puzzleLine)) {
|
||||||
|
// std::println("Ingredient: {}", puzzleLine);
|
||||||
|
puzzleInput.ingredients.emplace_back(std::stoll(puzzleLine));
|
||||||
|
}
|
||||||
|
|
||||||
|
// std::println("Ranges: {}\nIngredients: {}", puzzleInput.ingredients, puzzleInput.ingredients);
|
||||||
|
|
||||||
|
return std::move(puzzleInput);
|
||||||
|
}
|
||||||
|
|
||||||
|
static auto countFreshIngredients(const PuzzleInput &puzzleInput) -> long long {
|
||||||
|
const auto &freshRanges = puzzleInput.freshRanges;
|
||||||
|
const auto &ingredients = puzzleInput.ingredients;
|
||||||
|
long long totalFresh{};
|
||||||
|
std::println("Ranges: {}\nIngredients: {}", ingredients, ingredients);
|
||||||
|
for (const auto ingredient : ingredients) {
|
||||||
|
std::println("Checking {}", ingredient);
|
||||||
|
for (const auto &range : freshRanges) {
|
||||||
|
if (ingredient >= range.first && ingredient <= range.second) {
|
||||||
|
std::println("{} fits in range: {}:{}", ingredient, range.first, range.second);
|
||||||
|
totalFresh += 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return totalFresh;
|
||||||
|
}
|
||||||
|
|
||||||
|
static long long countAll(const std::ranges::range auto &ranges) {
|
||||||
|
std::println("Final count:\n\n");
|
||||||
|
|
||||||
|
long long bigNum{};
|
||||||
|
for (const auto &range : ranges) {
|
||||||
|
std::println("{}:{}", range.first, range.second);
|
||||||
|
if (range == FreshRange(-1, -1)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
bigNum += range.second - range.first + 1;
|
||||||
|
}
|
||||||
|
return bigNum;
|
||||||
|
}
|
||||||
|
|
||||||
|
static auto countFreshIngredientsRange(std::vector<FreshRange> &ranges) -> long long {
|
||||||
|
std::ranges::sort(ranges);
|
||||||
|
std::list<FreshRange> rangeList;
|
||||||
|
rangeList.assign_range(ranges);
|
||||||
|
|
||||||
|
auto cur = rangeList.begin();
|
||||||
|
while (true) {
|
||||||
|
auto next = std::next(cur);
|
||||||
|
std::println("Starting with {}", *cur);
|
||||||
|
|
||||||
|
if (next == rangeList.end()) { // No need to compare against the end
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cur->second >= next->first) {
|
||||||
|
std::println("\t Merging! {}", *next);
|
||||||
|
cur->second = std::max(cur->second, next->second);
|
||||||
|
|
||||||
|
rangeList.erase(next);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
cur++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return countAll(rangeList);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto main() -> int {
|
||||||
|
auto testCase = parseInput("test_input");
|
||||||
|
if (testCase) {
|
||||||
|
|
||||||
|
// auto testResult = countFreshIngredients(*testCase);
|
||||||
|
// std::println("P1 Testcase result: {}", testResult);
|
||||||
|
|
||||||
|
auto testResultP2 = countFreshIngredientsRange((*testCase).freshRanges);
|
||||||
|
std::println("P2 Testcase result: {}", testResultP2);
|
||||||
|
} else {
|
||||||
|
std::print("{}\n", testCase.error());
|
||||||
|
}
|
||||||
|
|
||||||
|
auto realPuzzle = parseInput("puzzle_input");
|
||||||
|
if (realPuzzle) {
|
||||||
|
// auto realResult = countFreshIngredients(*realPuzzle);
|
||||||
|
// std::println("P1 Real result: {}", realResult);
|
||||||
|
|
||||||
|
auto realResultP2 = countFreshIngredientsRange((*realPuzzle).freshRanges);
|
||||||
|
std::println("P2 Real result: {}", realResultP2);
|
||||||
|
} else {
|
||||||
|
std::print("{}\n", realPuzzle.error());
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
1187
day5/puzzle_input
Normal file
1187
day5/puzzle_input
Normal file
File diff suppressed because it is too large
Load diff
12
day5/test_input
Normal file
12
day5/test_input
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
3-5
|
||||||
|
10-14
|
||||||
|
10-13
|
||||||
|
16-20
|
||||||
|
12-18
|
||||||
|
|
||||||
|
1
|
||||||
|
5
|
||||||
|
8
|
||||||
|
11
|
||||||
|
17
|
||||||
|
32
|
||||||
Loading…
Add table
Add a link
Reference in a new issue