Files
advent-of-code/2021/puzzle-04-01.cc

150 lines
3.6 KiB
C++

//
// Created by Matthew Gretton-Dann on 04/12/2021.
//
#include <array>
#include <iomanip>
#include <iostream>
#include <numeric>
#include <string>
#include <utility>
#include <vector>
using Number = unsigned long; // NOLINT(google-runtime-int)
using NumberVector = std::vector<Number>;
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<std::string, 5> 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<Number, bool>;
using NumberArray = std::array<NumberPair, 25>;
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<BingoCard> cards;
while (std::getline(std::cin, line)) {
assert(line.empty());
std::array<std::string, 5> 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;
}