finish day 2 part 1
This commit is contained in:
0
.clang-tidy
Normal file
0
.clang-tidy
Normal file
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,3 +1,5 @@
|
||||
cmake-*
|
||||
day1.dSYM
|
||||
build
|
||||
.idea
|
||||
.cache
|
||||
@@ -3,11 +3,9 @@ project(cpp)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 23)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fexperimental-library")
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS true)
|
||||
|
||||
add_library(cpp STATIC
|
||||
add_executable(cpp_tests
|
||||
doctest.h
|
||||
run_tests.cpp
|
||||
day1.cpp)
|
||||
|
||||
add_executable(cpp_tests run_tests.cpp)
|
||||
target_link_libraries(cpp_tests PRIVATE cpp)
|
||||
run_tests.cpp
|
||||
)
|
||||
|
||||
152
day2.cpp
Normal file
152
day2.cpp
Normal file
@@ -0,0 +1,152 @@
|
||||
#include <cassert>
|
||||
#include <charconv>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <ranges>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
#include "doctest.h"
|
||||
|
||||
namespace day2 {
|
||||
const std::string sample =
|
||||
"11-22,95-115,998-1012,1188511880-1188511890,222220-222224,1698522-1698528,"
|
||||
"446443-446449,38593856-38593862,565653-565659,824824821-824824827,"
|
||||
"2121212118-2121212124";
|
||||
|
||||
struct Range {
|
||||
uint64_t start;
|
||||
uint64_t end;
|
||||
};
|
||||
} // namespace day2
|
||||
|
||||
template<>
|
||||
struct std::formatter<day2::Range> : std::formatter<std::string_view> {
|
||||
static auto format(const day2::Range &i, std::format_context &ctx) {
|
||||
return std::format_to(ctx.out(), "Range[start: {}, end: {}]", i.start,i.end);
|
||||
}
|
||||
};
|
||||
|
||||
namespace day2 {
|
||||
Range parse_range(std::string_view s) {
|
||||
std::string_view start;
|
||||
std::string_view end;
|
||||
|
||||
for (size_t i = 0; i < s.size(); i++) {
|
||||
const char c = s[i];
|
||||
if (c == '-') {
|
||||
start = {s.data(), i};
|
||||
end = {s.data() + i + 1, s.size() - start.size()};
|
||||
}
|
||||
}
|
||||
|
||||
Range range;
|
||||
uint64_t parsed;
|
||||
std::from_chars(start.data(), start.end(), parsed);
|
||||
range.start = parsed;
|
||||
std::from_chars(end.data(), end.end(), parsed);
|
||||
range.end = parsed;
|
||||
return range;
|
||||
}
|
||||
|
||||
size_t find_divisor(uint64_t n) {
|
||||
for (size_t i = 1;; i++) {
|
||||
size_t div = n / std::pow(10, i);
|
||||
if (div == 0) {
|
||||
return std::pow(10, (i / 2));
|
||||
}
|
||||
}
|
||||
assert(0 && "Unreachable");
|
||||
}
|
||||
|
||||
uint64_t count_repetitions(const Range range) {
|
||||
uint64_t total = 0;
|
||||
for (uint64_t n = range.start; n <= range.end; n++) {
|
||||
auto div = find_divisor(n);
|
||||
auto left = n / div;
|
||||
auto right = n % div;
|
||||
if (left == right) total++;
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
uint64_t sum_repetitions(const Range range) {
|
||||
uint64_t total = 0;
|
||||
for (uint64_t n = range.start; n <= range.end; n++) {
|
||||
auto div = find_divisor(n);
|
||||
auto left = n / div;
|
||||
auto right = n % div;
|
||||
if (left == right) total += n;
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
uint64_t solve_first(std::string_view input) {
|
||||
uint64_t result = 0;
|
||||
for (const auto range :
|
||||
std::views::split(input, ',') | std::views::transform([](auto s) {
|
||||
return parse_range(std::string_view(s));
|
||||
})) {
|
||||
result += sum_repetitions(range);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
uint64_t sum_repetitions_2(const Range range, std::string& buf) {
|
||||
uint64_t total = 0;
|
||||
for (uint64_t n = range.start; n <= range.end; n++) {
|
||||
std::format_to(buf, "{}", n);
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
uint64_t solve_second(std::string_view input) {
|
||||
std::string buf;
|
||||
buf.reserve(100);
|
||||
uint64_t result = 0;
|
||||
for (const auto range :
|
||||
std::views::split(input, ',') | std::views::transform([](auto s) {
|
||||
return parse_range(std::string_view(s));
|
||||
})) {
|
||||
result += sum_repetitions_2(range, buf);
|
||||
buf.clear();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("Can parse input") {
|
||||
auto range = parse_range("11-22");
|
||||
CHECK(range.start == 11);
|
||||
CHECK(range.end == 22);
|
||||
}
|
||||
|
||||
TEST_CASE("Solve first sample") {
|
||||
CHECK(solve_first(sample) == 1227775554);
|
||||
}
|
||||
|
||||
TEST_CASE("Solve first input") {
|
||||
std::ifstream fs("day2input.txt");
|
||||
std::stringstream ss{};
|
||||
ss << fs.rdbuf();
|
||||
CHECK(solve_first(ss.str()) == 1227775554);
|
||||
}
|
||||
|
||||
TEST_CASE("Find divisor works") {
|
||||
CHECK(find_divisor(11) == 10);
|
||||
CHECK(find_divisor(1221) == 100);
|
||||
CHECK(find_divisor(222222) == 1000);
|
||||
}
|
||||
|
||||
TEST_CASE("Count repetition works") {
|
||||
CHECK(count_repetitions({.start = 11, .end = 22}) == 2);
|
||||
CHECK(count_repetitions({.start = 1188511880, .end = 1188511890}) == 1);
|
||||
}
|
||||
|
||||
} // namespace day2
|
||||
1
day2input.txt
Normal file
1
day2input.txt
Normal file
@@ -0,0 +1 @@
|
||||
655-1102,2949-4331,885300-1098691,1867-2844,20-43,4382100-4484893,781681037-781860439,647601-734894,2-16,180-238,195135887-195258082,47-64,4392-6414,6470-10044,345-600,5353503564-5353567532,124142-198665,1151882036-1151931750,6666551471-6666743820,207368-302426,5457772-5654349,72969293-73018196,71-109,46428150-46507525,15955-26536,65620-107801,1255-1813,427058-455196,333968-391876,482446-514820,45504-61820,36235767-36468253,23249929-23312800,5210718-5346163,648632326-648673051,116-173,752508-837824
|
||||
@@ -5,3 +5,4 @@
|
||||
#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
|
||||
#include "doctest.h"
|
||||
#include "day1.cpp"
|
||||
#include "day2.cpp"
|
||||
|
||||
Reference in New Issue
Block a user