Skip to content

Commit a6af5b9

Browse files
btblacktea
authored andcommitted
Implemented the second part of day2
1 parent 0918038 commit a6af5b9

File tree

3 files changed

+130
-84
lines changed

3 files changed

+130
-84
lines changed

CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,11 @@ endfunction(add_challenge)
1414

1515
add_challenge(day1)
1616
add_challenge(day1_part2)
17-
add_challenge(day2_part1)
17+
add_challenge(day2)
1818
add_challenge(day3)
1919
add_challenge(day4)
2020
add_challenge(day5)
21+
add_challenge(day6)
2122

2223
### Day 7
2324
add_challenge(day7)

src/day2.cpp

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
#include <algorithm>
2+
#include <iostream>
3+
#include <fstream>
4+
#include <charconv>
5+
#include <vector>
6+
#include <stdexcept>
7+
#include <span>
8+
9+
namespace {
10+
void parseLevels(const std::string& report, std::vector<int>& out)
11+
{
12+
if(report.empty()) return;
13+
14+
const char *begin = &report[0];
15+
const char * const end = &report[report.size()];
16+
std::from_chars_result result{};
17+
int val{};
18+
while(begin != end) {
19+
result = std::from_chars(begin, end, val);
20+
if(result.ec != std::errc()) {
21+
std::cerr << "\nreport: " << report;
22+
throw std::logic_error{"Invalid report input string"};
23+
}
24+
begin = std::min(result.ptr + 1, end);
25+
out.push_back(val);
26+
}
27+
}
28+
29+
template<typename S>
30+
[[nodiscard]] bool safe(std::span<const int> levels, const unsigned tolerate, const S& safer) noexcept
31+
{
32+
unsigned violations = 0;
33+
for (size_t i = 1; i < levels.size() && violations <= tolerate; ++i) {
34+
if (!safer(levels[i-1], levels[i])) {
35+
++violations;
36+
37+
if(i + 1 == levels.size()) break;
38+
39+
40+
// We have to figure out which value(i - 1 or i) have to be *removed.
41+
// This results in the next index position.
42+
43+
// Edge cases:
44+
// 59 62 65 64 65 <- 65(2nd) element should be removed
45+
// 36 34 36 33 30 <- 34(2nd) element should be removed
46+
47+
if(safer(levels[i - 1], levels[i + 1])) {
48+
++i;
49+
}
50+
// Prev should be deleted because current and next elements are safe.
51+
else if(safer(levels[i], levels[i + 1])) {
52+
// However, we must check that current element and prevous elements build safe consequence.
53+
if(i > 1) {
54+
// 1 2 3 10 12. 2 and 10 are not safe. This results in increase in violations.
55+
violations += !safer(levels[i - 2], levels[i]);
56+
}
57+
}
58+
}
59+
}
60+
return violations <= tolerate;
61+
}
62+
63+
[[nodiscard]] constexpr bool isLevelsSafe(int largelLevel, int smallerLevel) noexcept
64+
{
65+
const auto diff{largelLevel - smallerLevel};
66+
return 1 <= diff && diff <= 3;
67+
}
68+
69+
[[nodiscard]] bool isAscendingSafe(std::span<const int> levels, unsigned tolerate) noexcept
70+
{
71+
return safe(levels, tolerate, [](int smaller, int larger) {
72+
return isLevelsSafe(larger, smaller);
73+
});
74+
}
75+
76+
[[nodiscard]] bool isDescendingSafe(std::span<const int> levels, unsigned tolerate) noexcept
77+
{
78+
return safe(levels, tolerate, [](int larger, int smaller) {
79+
return isLevelsSafe(larger, smaller);
80+
});
81+
}
82+
83+
[[nodiscard]] bool isSafe(std::span<const int> levels, unsigned tolerateLevel) noexcept
84+
{
85+
return isAscendingSafe(levels, tolerateLevel) || isDescendingSafe(levels, tolerateLevel);
86+
}
87+
88+
void printHelp()
89+
{
90+
std::cerr << "\nUsage:\n"
91+
<< "The program requires 2 args: (part1, part2) and the path to the file."
92+
<< "\nFor example, ./day2 part1 data/day2.txt";
93+
}
94+
95+
} //< anonymous namespace
96+
97+
int main(int argc, char *argv[]) {
98+
if(argc != 3) {
99+
printHelp();
100+
return 1;
101+
}
102+
std::string_view task{argv[1]};
103+
if(task != "part1" && task != "part2") {
104+
std::cerr << "\nfirst arg can be either `part1` or `part2`\n";
105+
printHelp();
106+
return 1;
107+
}
108+
109+
std::ifstream ifile(argv[2]);
110+
if(!ifile) {
111+
std::cerr << "\nFile cannot be open";
112+
return 1;
113+
}
114+
115+
const unsigned tolerateLevel = task == "part1" ? 0 : 1;
116+
117+
size_t count{};
118+
std::string report;
119+
std::vector<int> levels;
120+
while(std::getline(ifile, report)) {
121+
levels.clear();
122+
parseLevels(report, levels);
123+
count += isSafe(levels, tolerateLevel);
124+
}
125+
std::cout << "\nanswer: " << count;
126+
127+
return 0;
128+
}

src/day2_part1.cpp

Lines changed: 0 additions & 83 deletions
This file was deleted.

0 commit comments

Comments
 (0)