Skip to content

Commit e265b7e

Browse files
author
Pascal Guenther
committed
2024 Day 02
1 parent 6ff1deb commit e265b7e

File tree

8 files changed

+1260
-3
lines changed

8 files changed

+1260
-3
lines changed

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
cmake_minimum_required(VERSION 3.16)
22

3-
project(AdventOfCode VERSION 2024.12.01)
3+
project(AdventOfCode VERSION 2024.12.02)
44

55
option(AOC_TESTING "Enable testing for AdventOfCode" On)
66

cpp/src/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ target_link_libraries(aoc_y2024_core PRIVATE
1212
ctre
1313
)
1414

15-
set(AOC_Y2024_DAYS_LIST "01")
15+
set(AOC_Y2024_DAYS_LIST "01;02")
1616
set(AOC_Y2024_DAYS_LIST ${AOC_Y2024_DAYS_LIST} PARENT_SCOPE)
1717
set(AOC_Y2024_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR} PARENT_SCOPE)
1818

cpp/src/day01.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
#include <algorithm>
77
#include <memory>
88
#include <numeric>
9-
#include <ranges>
109
#include <string_view>
1110
#include <utility>
1211
#include <vector>

cpp/src/day02.cpp

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
#include "ipuzzle.hpp"
2+
#include "puzzle_common.hpp"
3+
#include "utils.hpp"
4+
5+
#include <algorithm>
6+
#include <memory>
7+
#include <numeric>
8+
#include <ranges>
9+
#include <string_view>
10+
#include <utility>
11+
#include <vector>
12+
13+
namespace AOC::Y2024
14+
{
15+
16+
namespace {
17+
using Row = std::vector<unsigned int>;
18+
using Parsed = std::vector<Row>;
19+
20+
AOC_Y2024_CONSTEXPR auto parse_input(std::string_view input_string_view)
21+
{
22+
Parsed parsed;
23+
for(const auto &line : LinesView{input_string_view})
24+
{
25+
if(line.empty())
26+
{
27+
continue;
28+
}
29+
parsed.emplace_back(parse_to_vector_of_numbers<unsigned int, ' '>(line));
30+
}
31+
return parsed;
32+
}
33+
34+
AOC_Y2024_CONSTEXPR auto is_safe(const Row &row)
35+
{
36+
const auto numberOfLevels = row.size();
37+
bool increasing = true;
38+
bool decreasing = true;
39+
for(size_t idx = 0u; idx != (numberOfLevels - 1ul); ++idx)
40+
{
41+
const auto level = row[idx];
42+
const auto nextLevel = row[idx + 1u];
43+
increasing = increasing && level < nextLevel;
44+
decreasing = decreasing && level > nextLevel;
45+
if(!(decreasing || increasing))
46+
{
47+
return false;
48+
}
49+
const auto distance = (level > nextLevel) ? (level - nextLevel) : (nextLevel - level);
50+
if((distance < 1u) || (distance > 3))
51+
{
52+
return false;
53+
}
54+
}
55+
return true;
56+
}
57+
58+
AOC_Y2024_CONSTEXPR auto part_1(const auto &parsedInput)
59+
{
60+
return std::ranges::count_if(parsedInput, is_safe);
61+
}
62+
63+
AOC_Y2024_CONSTEXPR auto part_2(const auto &parsedInput)
64+
{
65+
const auto is_safe_with_dampener = [](const Row &row) {
66+
const auto numberOfLevels = row.size();
67+
if(numberOfLevels < 1u)
68+
{
69+
return false;
70+
}
71+
if(is_safe(row))
72+
{
73+
return true;
74+
}
75+
for(size_t drop = 0u; drop != numberOfLevels; ++drop)
76+
{
77+
Row rowWithOneElementDropped{row};
78+
rowWithOneElementDropped.erase(rowWithOneElementDropped.begin() + static_cast<ssize_t>(drop));
79+
if(is_safe(rowWithOneElementDropped))
80+
{
81+
return true;
82+
}
83+
}
84+
return false;
85+
};
86+
return std::ranges::count_if(parsedInput, is_safe_with_dampener);
87+
}
88+
}
89+
90+
class PuzzleDay02Impl final {
91+
public:
92+
AOC_Y2024_CONSTEXPR PuzzleDay02Impl(Parsed &&parsed) : parsed(parsed) {}
93+
Parsed parsed;
94+
};
95+
96+
AOC_Y2024_PUZZLE_CLASS_DECLARATION(02)
97+
98+
PuzzleDay02::PuzzleDay02(const std::string_view input)
99+
: pImpl(std::make_unique<PuzzleDay02Impl>(parse_input(input)))
100+
{
101+
}
102+
103+
PuzzleDay02::~PuzzleDay02() = default;
104+
105+
[[nodiscard]] IPuzzle::Solution_t PuzzleDay02::Part1()
106+
{
107+
if (!pImpl || (pImpl->parsed.size() < 1))
108+
{
109+
return std::monostate{};
110+
}
111+
return part_1(pImpl->parsed);
112+
}
113+
114+
[[nodiscard]] IPuzzle::Solution_t PuzzleDay02::Part2()
115+
{
116+
if (!pImpl || (pImpl->parsed.size() < 1))
117+
{
118+
return std::monostate{};
119+
}
120+
return part_2(pImpl->parsed);
121+
}
122+
123+
#if AOC_Y2024_CONSTEXPR_UNIT_TEST
124+
namespace
125+
{
126+
constexpr const char * exampleInput = R"DAY02(
127+
7 6 4 2 1
128+
1 2 7 8 9
129+
9 7 6 2 1
130+
1 3 2 4 5
131+
8 6 4 4 1
132+
1 3 6 7 9
133+
)DAY02";
134+
consteval bool TestDay02()
135+
{
136+
Parsed parsed{parse_input(exampleInput)};
137+
138+
if (2 != part_1(parsed))
139+
{
140+
return false;
141+
}
142+
143+
return 4 == part_2(parsed);
144+
}
145+
146+
static_assert(TestDay02(), "");
147+
} // namespace
148+
#endif // AOC_Y2024_CONSTEXPR_UNIT_TEST
149+
150+
} // namespace AOC::Y2024

cpp/tests/test_day02.cpp

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
2+
#include "ipuzzle.hpp"
3+
#include "puzzle_common.hpp"
4+
5+
#include <gtest/gtest.h>
6+
7+
#include <memory>
8+
#include <string_view>
9+
10+
namespace AOC::Y2024
11+
{
12+
13+
AOC_Y2024_PUZZLE_CLASS_DECLARATION(02)
14+
15+
namespace
16+
{
17+
18+
class Day02Test : public ::testing::Test
19+
{
20+
protected:
21+
void SetUp() override
22+
{
23+
pPuzzle = std::make_unique<PuzzleDay02>(exampleInput);
24+
}
25+
26+
// void TearDown() override {}
27+
std::unique_ptr<IPuzzle> pPuzzle;
28+
static constexpr const char * exampleInput = R"DAY02(
29+
7 6 4 2 1
30+
1 2 7 8 9
31+
9 7 6 2 1
32+
1 3 2 4 5
33+
8 6 4 4 1
34+
1 3 6 7 9
35+
)DAY02";
36+
};
37+
38+
TEST_F(Day02Test, Part1)
39+
{
40+
ASSERT_EQ(std::get<std::int64_t>(pPuzzle->Part1()), 2);
41+
}
42+
43+
TEST_F(Day02Test, Part2)
44+
{
45+
ASSERT_EQ(std::get<std::int64_t>(pPuzzle->Part2()), 4);
46+
}
47+
48+
} // namespace
49+
} // namespace AOC::Y2024

0 commit comments

Comments
 (0)