150 lines
3.6 KiB
C++
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;
|
|
} |