refactor utils
This commit is contained in:
35
day1.cpp
35
day1.cpp
@@ -5,11 +5,11 @@
|
||||
#include <cassert>
|
||||
#include <charconv>
|
||||
#include <ranges>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
#include "doctest.h"
|
||||
#include "utils.h"
|
||||
|
||||
namespace day1 {
|
||||
enum Direction {
|
||||
L = 'L',
|
||||
R = 'R',
|
||||
@@ -27,15 +27,17 @@ Instruction parse_instruction(std::string_view line) {
|
||||
std::from_chars(&line[1], line.data() + line.size(), amount);
|
||||
return Instruction{direction, amount};
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
struct std::formatter<Instruction> : std::formatter<string_view> {
|
||||
static auto format(const Instruction &i, std::format_context &ctx) {
|
||||
struct std::formatter<day1::Instruction> : std::formatter<string_view> {
|
||||
static auto format(const day1::Instruction &i, std::format_context &ctx) {
|
||||
return std::format_to(ctx.out(), "Instruction[direction: {}, amount: {}]", static_cast<char>(i.direction),
|
||||
i.amount);
|
||||
}
|
||||
};
|
||||
|
||||
namespace day1 {
|
||||
const std::string sample =
|
||||
"L68\n"
|
||||
"L30\n"
|
||||
@@ -79,9 +81,9 @@ uint32_t solve_first(const std::string &input) {
|
||||
uint32_t spins = 0;
|
||||
|
||||
for (const auto instr:
|
||||
std::views::split(input, '\n')
|
||||
| std::views::transform([](auto s) { return std::string_view(s); })
|
||||
| std::views::filter([](const std::string_view s) { return !s.empty(); })
|
||||
std::views::split(std::string_view{input}, '\n')
|
||||
| std::views::transform(utils::to_string_view)
|
||||
| std::views::filter(utils::non_empty)
|
||||
| std::views::transform(parse_instruction)
|
||||
) {
|
||||
if (spin(value, instr)) {
|
||||
@@ -96,11 +98,7 @@ uint32_t solve_first(const std::string &input) {
|
||||
TEST_SUITE_BEGIN("Day 1");
|
||||
TEST_CASE("puzzle 1") {
|
||||
CHECK(solve_first(sample) == 3);
|
||||
std::ifstream input("day1input.txt");
|
||||
CHECK(input.is_open());
|
||||
std::stringstream buffer;
|
||||
buffer << input.rdbuf();
|
||||
CHECK(solve_first(buffer.str()) == 1158);
|
||||
CHECK(solve_first(utils::read_file("day1input.txt")) == 1158);
|
||||
}
|
||||
|
||||
uint32_t solve_second(const std::string &input) {
|
||||
@@ -108,9 +106,9 @@ uint32_t solve_second(const std::string &input) {
|
||||
uint32_t spins = 0;
|
||||
|
||||
for (const auto instr:
|
||||
std::views::split(input, '\n')
|
||||
| std::views::transform([](auto s) { return std::string_view(s); })
|
||||
| std::views::filter([](const std::string_view s) { return !s.empty(); })
|
||||
std::views::split(std::string_view{input}, '\n')
|
||||
| std::views::transform(utils::to_string_view)
|
||||
| std::views::filter(utils::non_empty)
|
||||
| std::views::transform(parse_instruction)
|
||||
) {
|
||||
spins += spin2(value, instr);
|
||||
@@ -122,11 +120,8 @@ uint32_t solve_second(const std::string &input) {
|
||||
|
||||
TEST_CASE("puzzle 2") {
|
||||
CHECK(solve_second(sample) == 6);
|
||||
std::ifstream input("day1input.txt");
|
||||
CHECK(input.is_open());
|
||||
std::stringstream buffer;
|
||||
buffer << input.rdbuf();
|
||||
CHECK(solve_second(buffer.str()) == 6860);
|
||||
CHECK(solve_second(utils::read_file("day1input.txt")) == 6860);
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
||||
}
|
||||
|
||||
27
day2.cpp
27
day2.cpp
@@ -1,13 +1,12 @@
|
||||
#include <cassert>
|
||||
#include <charconv>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <ranges>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
#include "doctest.h"
|
||||
#include "utils.h"
|
||||
|
||||
namespace day2 {
|
||||
const std::string sample =
|
||||
@@ -87,9 +86,9 @@ uint64_t sum_repetitions(const Range range) {
|
||||
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));
|
||||
})) {
|
||||
std::views::split(input, ',')
|
||||
| std::views::transform(utils::to_string_view)
|
||||
| std::views::transform(parse_range)) {
|
||||
result += sum_repetitions(range);
|
||||
}
|
||||
|
||||
@@ -129,9 +128,9 @@ uint64_t solve_second(std::string_view input) {
|
||||
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));
|
||||
})) {
|
||||
std::views::split(input, ',')
|
||||
| std::views::transform(utils::to_string_view)
|
||||
| std::views::transform(parse_range)) {
|
||||
result += sum_repetitions_2(range, buf);
|
||||
buf.clear();
|
||||
}
|
||||
@@ -152,10 +151,7 @@ TEST_CASE("Solve first sample") {
|
||||
}
|
||||
|
||||
TEST_CASE("Solve first input") {
|
||||
std::ifstream fs("day2input.txt");
|
||||
std::stringstream ss{};
|
||||
ss << fs.rdbuf();
|
||||
CHECK(solve_first(ss.str()) == 21898734247);
|
||||
CHECK(solve_first(utils::read_file("day2input.txt")) == 21898734247);
|
||||
}
|
||||
|
||||
TEST_CASE("Find divisor works") {
|
||||
@@ -184,11 +180,8 @@ TEST_CASE("Solves second sample") {
|
||||
TEST_CASE(
|
||||
"Solves second input"
|
||||
* doctest::skip(true)
|
||||
) {
|
||||
std::ifstream fs("day2input.txt");
|
||||
std::stringstream ss{};
|
||||
ss << fs.rdbuf();
|
||||
CHECK(solve_second(ss.view()) == 28915664389);
|
||||
) {
|
||||
CHECK(solve_second(utils::read_file("day2input.txt")) == 28915664389);
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
||||
|
||||
21
day3.cpp
21
day3.cpp
@@ -4,9 +4,8 @@
|
||||
|
||||
#include <ranges>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include "doctest.h"
|
||||
#include "utils.h"
|
||||
|
||||
namespace day3 {
|
||||
const std::string sample = "987654321111111\n"
|
||||
@@ -16,12 +15,8 @@ const std::string sample = "987654321111111\n"
|
||||
|
||||
auto split_into_banks(const std::string_view input) {
|
||||
return std::views::split(input, '\n')
|
||||
| std::views::filter([](const auto &s) {
|
||||
return !s.empty();
|
||||
})
|
||||
| std::views::transform([](const auto &x) {
|
||||
return std::string_view(x);
|
||||
});
|
||||
| std::views::transform(utils::to_string_view)
|
||||
| std::views::filter(utils::non_empty);
|
||||
}
|
||||
|
||||
uint64_t solve(const std::string_view input, uint8_t num_batteries) {
|
||||
@@ -58,10 +53,7 @@ TEST_CASE("solve first sample") {
|
||||
}
|
||||
|
||||
TEST_CASE("solve first puzzle") {
|
||||
std::ifstream input("day3input.txt");
|
||||
std::stringstream buf;
|
||||
buf << input.rdbuf();
|
||||
CHECK(solve(buf.view(),2) == 17095);
|
||||
CHECK(solve(utils::read_file("day3input.txt"),2) == 17095);
|
||||
}
|
||||
|
||||
TEST_CASE("solve second sample") {
|
||||
@@ -69,10 +61,7 @@ TEST_CASE("solve second sample") {
|
||||
}
|
||||
|
||||
TEST_CASE("solve second input") {
|
||||
std::ifstream input("day3input.txt");
|
||||
std::stringstream buf;
|
||||
buf << input.rdbuf();
|
||||
CHECK(solve(buf.view(), 12) == 168794698570517);
|
||||
CHECK(solve(utils::read_file("day3input.txt"), 12) == 168794698570517);
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
||||
|
||||
19
day4.cpp
19
day4.cpp
@@ -27,8 +27,8 @@ enum class Point : char {
|
||||
Empty = '.',
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
std::array<char, 8> get_surrounding(const std::vector<T> &lines, size_t x, size_t y) noexcept {
|
||||
template<utils::StringLike T>
|
||||
std::array<char, 8> get_surrounding(const std::vector<T> &lines, const size_t x, const size_t y) noexcept {
|
||||
std::array<char, 8> points = {};
|
||||
size_t i = 0;
|
||||
for (int dy = -1; dy < 2; ++dy) {
|
||||
@@ -48,16 +48,15 @@ std::array<char, 8> get_surrounding(const std::vector<T> &lines, size_t x, size_
|
||||
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::views::transform(utils::to_string_view)
|
||||
| std::views::filter(utils::non_empty)
|
||||
| std::ranges::to<std::vector>();
|
||||
|
||||
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;
|
||||
if (lines[y][x] != '@') continue;
|
||||
size_t num_paper = 0;
|
||||
for (const char p: get_surrounding(lines, x, y)) {
|
||||
if (p == '@') {
|
||||
@@ -77,7 +76,7 @@ uint32_t solve_first(const std::string_view input) noexcept {
|
||||
return accessible;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
template<utils::StringLike T>
|
||||
std::vector<std::tuple<size_t, size_t> > remove_paper(const std::vector<T> &lines) {
|
||||
std::vector<std::tuple<size_t, size_t> > removable = {};
|
||||
|
||||
@@ -110,7 +109,7 @@ uint32_t solve_second(const std::string_view input) {
|
||||
| std::views::transform([](const auto r) {
|
||||
return std::string(r.data(), r.size());
|
||||
})
|
||||
| std::views::filter([](const auto &s) { return !s.empty(); })
|
||||
| std::views::filter(utils::non_empty)
|
||||
| std::ranges::to<std::vector>();
|
||||
bool removed = false;
|
||||
uint32_t total_removed = 0;
|
||||
@@ -136,7 +135,7 @@ TEST_CASE("solves first sample") {
|
||||
}
|
||||
|
||||
TEST_CASE("solves first puzzle") {
|
||||
CHECK(solve_first(read_file("day4input.txt")) == 1626);
|
||||
CHECK(solve_first(utils::read_file("day4input.txt")) == 1626);
|
||||
}
|
||||
|
||||
|
||||
@@ -145,7 +144,7 @@ TEST_CASE("solves second sample") {
|
||||
}
|
||||
|
||||
TEST_CASE("solves second puzzle") {
|
||||
CHECK(solve_second(read_file("day4input.txt")) == 9173);
|
||||
CHECK(solve_second(utils::read_file("day4input.txt")) == 9173);
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
||||
|
||||
16
utils.h
16
utils.h
@@ -7,13 +7,27 @@
|
||||
#include <sstream>
|
||||
#include <string_view>
|
||||
|
||||
constexpr std::string_view to_string_view(const std::ranges::subrange<const char *> cs) {
|
||||
namespace utils {
|
||||
|
||||
template<typename T>
|
||||
concept StringLike = requires(const T &t)
|
||||
{
|
||||
{ std::string_view{t} } -> std::convertible_to<std::string_view>;
|
||||
{ t.size() } -> std::convertible_to<size_t>;
|
||||
};
|
||||
|
||||
constexpr std::string_view to_string_view(const std::ranges::subrange<const char *>& cs) {
|
||||
return std::string_view{cs.data(), cs.size()};
|
||||
}
|
||||
|
||||
constexpr bool non_empty(const std::string_view sv) {
|
||||
return !sv.empty();
|
||||
}
|
||||
|
||||
inline std::string read_file(std::string_view path) {
|
||||
std::ifstream input(path.data());
|
||||
std::stringstream buffer;
|
||||
buffer << input.rdbuf();
|
||||
return buffer.str();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user