From b6213c659319cc92ef9a2e71bded528157eaa547 Mon Sep 17 00:00:00 2001 From: Matthew Gretton-Dann Date: Fri, 3 Dec 2021 12:32:15 +0000 Subject: [PATCH] Tidy up 2021 day 3 puzzle 2 code. This adds some comments and removes code duplication. --- 2021/puzzle-03-02.cc | 54 ++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 30 deletions(-) diff --git a/2021/puzzle-03-02.cc b/2021/puzzle-03-02.cc index bc91316..f5bffda 100644 --- a/2021/puzzle-03-02.cc +++ b/2021/puzzle-03-02.cc @@ -8,18 +8,35 @@ #include #include +/** \brief Convert the string s to a number + * @param s String of 1s and 0s to convert + * @return Value of string + */ auto to_num(std::string const& s) -> std::uint64_t { std::uint64_t result{0}; for (auto c : s) { + assert(c == '1' || c == '0'); result <<= 1; - result |= (c == '1' ? 1 : 0); + result |= (c == '1') ? 1 : 0; } return result; } -auto find_oxygen_rating(std::vector const& lines) -> std::string +/** \brief Find the rating for a given selector and set of lines. + * + * @tparam Fn Selector function type + * @param lines Lines to select from + * @param selector Takes bool saying whether ones are predominant, should return character to keep. + * @return String of selected number. + */ +template +auto find_rating(std::vector const& lines, Fn selector) -> std::string { + /* Algorithm description: We copy the given lines and then for each index in the strings in turn + * we see how many 1 digits are in that index. The function \a selector is then called to get the + * character to keep, before erasing the strings we do not want to keep. + */ std::vector data{lines}; assert(!data.empty()); std::size_t len{data[1].size()}; @@ -27,32 +44,7 @@ auto find_oxygen_rating(std::vector const& lines) -> std::string auto one_bits{std::accumulate( data.begin(), data.end(), std::uint64_t{0}, [i](std::uint64_t a, std::string const& s) { return a + (s[i] == '1' ? 1 : 0); })}; - char keep{(one_bits * 2 >= data.size()) ? '1' : '0'}; - std::cout << "Size of data = " << data.size() << " Number of one bits = " << one_bits - << " keeping " << keep << '\n'; - auto it{std::remove_if(data.begin(), data.end(), - [keep, i](std::string const& s) { return s[i] != keep; })}; - data.erase(it, data.end()); - if (data.size() <= 1) { - break; - } - } - assert(data.size() == 1); - return data[0]; -} - -auto find_co2_rating(std::vector const& lines) -> std::string -{ - std::vector data{lines}; - assert(!data.empty()); - std::size_t len{data[1].size()}; - for (std::size_t i{0}; i < len; ++i) { - auto one_bits{std::accumulate( - data.begin(), data.end(), std::uint64_t{0}, - [i](std::uint64_t a, std::string const& s) { return a + (s[i] == '1' ? 1 : 0); })}; - char keep{(one_bits * 2 >= data.size()) ? '0' : '1'}; - std::cout << "Size of data = " << data.size() << " Number of one bits = " << one_bits - << " keeping " << keep << '\n'; + char keep{selector(one_bits * 2 >= data.size())}; auto it{std::remove_if(data.begin(), data.end(), [keep, i](std::string const& s) { return s[i] != keep; })}; data.erase(it, data.end()); @@ -72,8 +64,10 @@ auto main() -> int lines.push_back(line); } - auto oxygen_rating{to_num(find_oxygen_rating(lines))}; - auto co2_rating{to_num(find_co2_rating(lines))}; + auto oxygen_rating{ + to_num(find_rating(lines, [](bool mostly_ones) { return mostly_ones ? '1' : '0'; }))}; + auto co2_rating{ + to_num(find_rating(lines, [](bool mostly_ones) { return mostly_ones ? '0' : '1'; }))}; std::cout << "Oxygen generator rating * CO2 scrubber rating = " << oxygen_rating << " * " << co2_rating << " = " << oxygen_rating * co2_rating << '\n';