// // Created by Grant Horner on 12/4/25. // #include #include #include #include "doctest.h" #include "utils.h" namespace day4 { const std::string sample = "..@@.@@@@.\n" "@@@.@.@.@@\n" "@@@@@.@.@@\n" "@.@@@@..@.\n" "@@.@@@@.@@\n" ".@@@@@@@.@\n" ".@.@.@.@@@\n" "@.@@@.@@@@\n" ".@@@@@@@@.\n" "@.@.@@@.@.\n"; enum class Point : char { Paper = '@', Empty = '.', }; template std::array get_surrounding(const std::vector &lines, size_t x, size_t y) noexcept { std::array points = {}; size_t i = 0; for (int dy = -1; dy < 2; ++dy) { if (y + dy < 0 || y + dy >= lines.size()) { continue; } for (int dx = -1; dx < 2; ++dx) { if (x + dx < 0 || x + dx >= lines[0].size()) { continue; } if (dx == 0 && dy == 0) continue; points[i] = lines[y + dy][x + dx]; i++; } } return points; } uint32_t solve_first(const std::string_view input) noexcept { const auto lines = std::string_view{input} | std::views::split('\n') | std::views::transform(to_string_view) | std::views::filter([](const auto s) { return !s.empty(); }) | std::ranges::to(); uint32_t accessible = 0; for (size_t y = 0; y < lines.size(); ++y) { for (size_t x = 0; x < lines[0].size(); ++x) { const auto c = lines[y][x]; if (c != '@') continue; size_t num_paper = 0; for (const char p: get_surrounding(lines, x, y)) { if (p == '@') { num_paper++; } if (num_paper == 4) { break; } } if (num_paper < 4) { accessible++; } } } return accessible; } template std::vector > remove_paper(const std::vector &lines) { std::vector > removable = {}; for (size_t y = 0; y < lines.size(); ++y) { for (size_t x = 0; x < lines[0].size(); ++x) { const auto c = lines[y][x]; if (c != '@') continue; size_t num_paper = 0; for (const char p: get_surrounding(lines, x, y)) { if (p == '@') { num_paper++; } if (num_paper == 4) { break; } } if (num_paper < 4) { removable.emplace_back(x, y); } } } return removable; } uint32_t solve_second(const std::string_view input) { std::vector lines = std::string_view{input} | std::views::split('\n') | std::views::transform([](const auto r) { return std::string(r.data(), r.size()); }) | std::views::filter([](const auto &s) { return !s.empty(); }) | std::ranges::to(); bool removed = false; uint32_t total_removed = 0; do { removed = false; const auto removable = remove_paper(lines); if (!removable.empty()) { removed = true; } for (auto [x, y]: removable) { lines[y][x] = '.'; total_removed++; } } while (removed); return total_removed; } TEST_SUITE_BEGIN("Day 4"); TEST_CASE("solves first sample") { CHECK(solve_first(sample) == 13); } TEST_CASE("solves first puzzle") { CHECK(solve_first(read_file("day4input.txt")) == 1626); } TEST_CASE("solves second sample") { CHECK(solve_second(sample) == 43); } TEST_CASE("solves second puzzle") { CHECK(solve_second(read_file("day4input.txt")) == 9173); } TEST_SUITE_END(); }