From 176d655e3c0a828a200b7e7ae9b184689644cfcb Mon Sep 17 00:00:00 2001 From: Matthew Gretton-Dann Date: Sat, 4 Dec 2021 08:04:02 +0000 Subject: [PATCH] Add 2021 Day 4 puzzles --- 2021/puzzle-04-01.cc | 150 +++++++++++++++++++++++++++++++++++++++++ 2021/puzzle-04-02.cc | 154 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 304 insertions(+) create mode 100644 2021/puzzle-04-01.cc create mode 100644 2021/puzzle-04-02.cc diff --git a/2021/puzzle-04-01.cc b/2021/puzzle-04-01.cc new file mode 100644 index 0000000..1fff0a5 --- /dev/null +++ b/2021/puzzle-04-01.cc @@ -0,0 +1,150 @@ +// +// Created by Matthew Gretton-Dann on 04/12/2021. +// + +#include +#include +#include +#include +#include +#include +#include + +using Number = unsigned long; // NOLINT(google-runtime-int) +using NumberVector = std::vector; + +auto parse_number_list(std::string const& s) -> NumberVector +{ + std::size_t idx{0}; + NumberVector result; + while (idx < s.size()) { + std::size_t end{0}; + result.push_back(std::stoul(s.substr(idx), &end)); + idx += end; + while (idx < s.size() && s[idx] == ',') { + ++idx; + } + } + return result; +} + +struct BingoCard +{ +public: + explicit BingoCard(std::array const& card) + { + unsigned row{0}; + for (auto const& s : card) { + std::size_t idx{0}; + for (unsigned col{0}; col < 5; ++col) { + while (s.at(idx) == ' ') { + ++idx; + } + std::size_t end{0}; + numbers_.at(row + col) = {std::stoul(s.substr(idx), &end), false}; + idx += end; + } + assert(idx == s.size()); + + row += 5; + } + } + + void mark(unsigned num) + { + for (auto it{// NOLINT(llvm-qualified-auto,readability-qualified-auto) + find_num(numbers_.begin(), numbers_.end(), num)}; + it != numbers_.end(); it = find_num(++it, numbers_.end(), num)) { + it->second = true; + } + } + + [[nodiscard]] auto bingo() const -> bool + { + for (unsigned row{0}; row < 25; row += 5) { + if (std::all_of(numbers_.begin() + row, numbers_.begin() + row + 5, + [](auto const& n) { return n.second; })) { + return true; + } + } + + for (unsigned col{0}; col < 5; ++col) { + unsigned marked_count{0}; + for (unsigned row{col}; row < 25; row += 5) { + if (numbers_.at(row).second) { + ++marked_count; + } + } + if (marked_count == 5) { + return true; + } + } + + return false; + } + + [[nodiscard]] auto score() const -> Number + { + return std::accumulate(numbers_.begin(), numbers_.end(), Number{0}, + [](Number a, auto const& n) { return a + (n.second ? 0 : n.first); }); + } + + auto print(std::ostream& os) const -> std::ostream& + { + for (unsigned i = 0; i < 25; ++i) { + os << std::setw(3) << numbers_.at(i).first << (numbers_.at(i).second ? "!" : " ") + << ((i % 5 == 4) ? '\n' : ' '); + } + return os; + } + +private: + using NumberPair = std::pair; + using NumberArray = std::array; + + static auto find_num(NumberArray::iterator begin, NumberArray::iterator end, Number num) + -> NumberArray ::iterator + { + return std::find_if(begin, end, [num](auto const& n) { return n.first == num; }); + } + + NumberArray numbers_; +}; + +auto main() -> int +{ + std::string line; + + if (!getline(std::cin, line)) { + std::cerr << "Unable to read random numbers.\n"; + return 1; + } + NumberVector random_numbers{parse_number_list(line)}; + + std::vector cards; + while (std::getline(std::cin, line)) { + assert(line.empty()); + std::array lines; + for (unsigned row{0}; row < 5; ++row) { + std::getline(std::cin, lines.at(row)); + } + cards.emplace_back(lines); + } + + for (auto num : random_numbers) { + std::cout << num << ", "; + for (auto& card : cards) { + card.mark(num); + if (card.bingo()) { + auto score{card.score()}; + std::cout << "\nBINGO " << score << " * " << num << " = " << score * num << '\n'; + card.print(std::cout); + std::cout << "Num cards: " << cards.size() << '\n'; + return 0; + } + } + } + + std::cerr << "No bingo!\n"; + return 1; +} \ No newline at end of file diff --git a/2021/puzzle-04-02.cc b/2021/puzzle-04-02.cc new file mode 100644 index 0000000..518fc6f --- /dev/null +++ b/2021/puzzle-04-02.cc @@ -0,0 +1,154 @@ +// +// Created by Matthew Gretton-Dann on 04/12/2021. +// + +#include +#include +#include +#include +#include +#include +#include + +using Number = unsigned long; // NOLINT(google-runtime-int) +using NumberVector = std::vector; + +auto parse_number_list(std::string const& s) -> NumberVector +{ + std::size_t idx{0}; + NumberVector result; + while (idx < s.size()) { + std::size_t end{0}; + result.push_back(std::stoul(s.substr(idx), &end)); + idx += end; + while (idx < s.size() && s[idx] == ',') { + ++idx; + } + } + return result; +} + +struct BingoCard +{ +public: + explicit BingoCard(std::array const& card) + { + unsigned row{0}; + for (auto const& s : card) { + std::size_t idx{0}; + for (unsigned col{0}; col < 5; ++col) { + while (s.at(idx) == ' ') { + ++idx; + } + std::size_t end{0}; + numbers_.at(row + col) = {std::stoul(s.substr(idx), &end), false}; + idx += end; + } + assert(idx == s.size()); + + row += 5; + } + } + + void mark(unsigned num) + { + for (auto it{// NOLINT(llvm-qualified-auto,readability-qualified-auto) + find_num(numbers_.begin(), numbers_.end(), num)}; + it != numbers_.end(); it = find_num(++it, numbers_.end(), num)) { + it->second = true; + } + } + + [[nodiscard]] auto bingo() const -> bool + { + for (unsigned row{0}; row < 25; row += 5) { + if (std::all_of(numbers_.begin() + row, numbers_.begin() + row + 5, + [](auto const& n) { return n.second; })) { + return true; + } + } + + for (unsigned col{0}; col < 5; ++col) { + unsigned marked_count{0}; + for (unsigned row{col}; row < 25; row += 5) { + if (numbers_.at(row).second) { + ++marked_count; + } + } + if (marked_count == 5) { + return true; + } + } + + return false; + } + + [[nodiscard]] auto score() const -> Number + { + return std::accumulate(numbers_.begin(), numbers_.end(), Number{0}, + [](Number a, auto const& n) { return a + (n.second ? 0 : n.first); }); + } + + auto print(std::ostream& os) const -> std::ostream& + { + for (unsigned i = 0; i < 25; ++i) { + os << std::setw(3) << numbers_.at(i).first << (numbers_.at(i).second ? "!" : " ") + << ((i % 5 == 4) ? '\n' : ' '); + } + return os; + } + +private: + using NumberPair = std::pair; + using NumberArray = std::array; + + static auto find_num(NumberArray::iterator begin, NumberArray::iterator end, Number num) + -> NumberArray ::iterator + { + return std::find_if(begin, end, [num](auto const& n) { return n.first == num; }); + } + + NumberArray numbers_; +}; + +auto main() -> int +{ + std::string line; + + if (!getline(std::cin, line)) { + std::cerr << "Unable to read random numbers.\n"; + return 1; + } + NumberVector random_numbers{parse_number_list(line)}; + + std::vector cards; + while (std::getline(std::cin, line)) { + assert(line.empty()); + std::array lines; + for (unsigned row{0}; row < 5; ++row) { + std::getline(std::cin, lines.at(row)); + } + cards.emplace_back(lines); + } + + auto num{random_numbers.begin()}; + while (cards.size() > 1 && num != random_numbers.end()) { + for (auto card{cards.begin()}; card != cards.end(); + card = (card->bingo() ? cards.erase(card) : ++card)) { + card->mark(*num); + } + ++num; + } + + assert(cards.size() == 1); + + while (!cards[0].bingo() && num != random_numbers.end()) { + cards[0].mark(*num++); + } + --num; + + auto score{cards[0].score()}; + std::cout << "\nBINGO " << score << " * " << *num << " = " << score * *num << '\n'; + cards[0].print(std::cout); + return 0; +} \ No newline at end of file