74 lines
1.7 KiB
C++
74 lines
1.7 KiB
C++
#include <algorithm>
|
|
#include <cstdint>
|
|
#include <iostream>
|
|
#include <tuple>
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
|
|
#include <doctest.h>
|
|
|
|
#include <aocpp/Startup.hpp>
|
|
|
|
namespace {
|
|
|
|
using Entry = std::tuple<std::size_t, std::size_t, char, std::string>;
|
|
|
|
auto Parse(std::string const& str) -> Entry
|
|
{
|
|
std::size_t lo, hi, n;
|
|
char letter;
|
|
auto res = std::sscanf(str.c_str(), "%zu-%zu %c: %zn", &lo, &hi, &letter, &n);
|
|
if (res != 3) { throw std::runtime_error{"bad input"}; }
|
|
return {lo, hi, letter, str.substr(n)};
|
|
}
|
|
|
|
auto Part1(Entry const& entry) -> bool {
|
|
auto const& [lo, hi, letter, text] = entry;
|
|
auto n = std::count(text.begin(), text.end(), letter);
|
|
return lo <= n && n <= hi;
|
|
}
|
|
|
|
auto Part2(Entry const& entry) -> bool
|
|
{
|
|
auto const& [lo, hi, letter, text] = entry;
|
|
return (text.at(lo-1) == letter) != (text.at(hi-1) == letter);
|
|
}
|
|
|
|
} // namespace
|
|
|
|
TEST_SUITE("documented examples") {
|
|
|
|
TEST_CASE("parser") {
|
|
REQUIRE(Parse("1-3 z: example") == Entry{1,3,'z',"example"});
|
|
}
|
|
|
|
TEST_CASE("part 1") {
|
|
REQUIRE( Part1(Parse("1-3 a: abcde")));
|
|
REQUIRE(!Part1(Parse("1-3 b: cdefg")));
|
|
REQUIRE( Part1(Parse("2-9 c: ccccccccc")));
|
|
}
|
|
|
|
TEST_CASE("part 2") {
|
|
REQUIRE( Part2(Parse("1-3 a: abcde")));
|
|
REQUIRE(!Part2(Parse("1-3 b: cdefg")));
|
|
REQUIRE(!Part2(Parse("2-9 c: ccccccccc")));
|
|
}
|
|
|
|
}
|
|
|
|
auto main(int argc, char** argv) -> int {
|
|
auto const in_ptr = aocpp::Startup(argc, argv);
|
|
auto & in = *in_ptr;
|
|
|
|
std::uint64_t part1{}, part2{};
|
|
|
|
std::string line;
|
|
while (std::getline(in, line)) {
|
|
auto entry = Parse(line);
|
|
if (Part1(entry)) part1++;
|
|
if (Part2(entry)) part2++;
|
|
}
|
|
std::cout << "Part 1: " << part1 << std::endl;
|
|
std::cout << "Part 2: " << part2 << std::endl;
|
|
}
|