[This is my first post here - though I have been lurking in the back reading, plussing, and hopefully learning for over two years]
Below is my solution for Advent of Code 2021 Day 4, where you are playing bingo against a giant squid.
You are given a set of bingo cards, and the list of numbers that will be drawn; the target for part 1 is to identify the bingo card that wins first, and for part 2, the card that wins last. For more details, check this link.
Some remarks:
- this is supposed to be developed against the clock. Therefore, reusability is not a very important consideration.
- error checking is not required, and not done. Bad input will blow everything apart; please ignore this.
- I work in a C++20 environment (but didn't necessarily use any features of it). I marked it C++20 because if C++20 offers something I missed, I want to learn about it.
What I am looking for:
- what is bad / poor / smelly?
- what could be improved?
- what could I do better using the C++20 feature set? I know about the capabilities, but didn't see any way to take advantage of it.
Here is the include BingoCard.h:
#pragma once #include <array> #include <iostream> #include <sstream> #include <vector> constexpr size_t BingoCardSize = 5; using Card = std::array<int, BingoCardSize* BingoCardSize>; class BingoCard { public: static BingoCard Create(std::istream& input); // construct by reading the numbers from input int DrawNumbers(const std::vector<int>& n) noexcept; // draw numbers till 'bingo' int GetRemainder() const noexcept; // get sum of numbers remaining after 'bingo' private: BingoCard(Card& n) noexcept : number(n) {} // constructor bool HasBingo() const noexcept; // check for 'bingo' private: const Card number; // numbers on the bingo card std::array<bool, BingoCardSize * BingoCardSize> hit{ false }; // flags if a number was hit }; Here the class code in BingoCard.cpp:
#include "BingoCard.h" BingoCard BingoCard::Create(std::istream& input) { Card n; for (int i = 0; i < n.size(); ++i) input >> n[i]; return BingoCard(n); } bool BingoCard::HasBingo(void) const noexcept // check for 'bingo'. note: diagonals are NOT considered 'bingo' { for (int i = 0; i < BingoCardSize; ++i) { bool row{ true }; bool col{ true }; for (int j = 0; j < BingoCardSize; ++j) { row &= hit[BingoCardSize * i + j]; // check along row col &= hit[i + BingoCardSize * j]; // check along column } if (row || col) return true; } return false; } int BingoCard::DrawNumbers(const std::vector<int>& draw) noexcept { for (int n = 0; n < draw.size(); ++n) { for (int j = 0; j < BingoCardSize * BingoCardSize; ++j) { if (number[j] == draw[n]) { hit[j] = true; if (HasBingo()) return n; break; } } } return draw.size(); } int BingoCard::GetRemainder(void) const noexcept { int sum{ 0 }; for (int i = 0; i < BingoCardSize * BingoCardSize; ++i) { if (!hit[i]) sum += number[i]; } return sum; } and here the main program:
#include "BingoCard.h" void AoC2021_04(std::istream& input) { std::string line{}; // read all numbers drawn during the game std::vector<int> draw{}; getline(input, line); std::istringstream str(line); int z0{ 0 }; while (str >> z0) { draw.emplace_back(z0); char comma{}; str >> comma; // read the comma and ignore it } // read all Bingocards std::vector<BingoCard> board{}; while (getline(input, line)) // the success of this blank line read means there is another board coming { board.emplace_back(BingoCard::Create(input)); } // find the BingoCards with the earliest [Part 1] and latest [Part 2] 'bingo' (that is, the minimum / maximum of DrawNumbers return value) int min{ std::numeric_limits<int>::max() }; int mini{ -1 }; int max{ 0 }; int maxi{ -1 }; for (int i = 0; i < board.size(); ++i) { auto n = board[i].DrawNumbers(draw); if (n < min) { min = n; mini = i; } if (n > max) { max = n; maxi = i; } } int z1 = board[mini].GetRemainder() * draw[min]; // AoC solution is min BingoCard's remainder times the winning number std::cout << "AoC2021 Day 4 Part 1: " << z1 << '\n'; int z2 = board[maxi].GetRemainder() * draw[max]; // AoC solution is max BingoCard's remainder times the winning number std::cout << "AoC2021 Day 4 Part 2: " << z2 << '\n'; } int main() { AoC2021_04(std::cin); } my input data (if you go to AoC and log in, you get a different input - everyone gets a slightly different one. I am quite sure the code above works for any input):
37,60,87,13,34,72,45,49,61,27,97,88,50,30,76,40,63,9,38,67,82,6,59,90,99,54,11,66,98,23,64,14,18,4,10,89,46,32,19,5,1,53,25,96,2,12,86,58,41,68,95,8,7,3,85,70,35,55,77,44,36,51,15,52,56,57,91,16,71,92,84,17,33,29,47,75,80,39,83,74,73,65,78,69,21,42,31,93,22,62,24,48,81,0,26,43,20,28,94,79 66 78 7 45 92 39 38 62 81 77 9 73 25 97 99 87 80 19 1 71 85 35 52 26 68 47 38 84 53 16 66 3 63 92 94 71 41 59 1 87 17 67 62 73 33 69 12 26 82 55 89 94 65 57 6 27 77 60 19 83 72 58 0 29 91 33 75 50 64 87 24 88 32 93 38 35 82 7 49 43 58 8 56 54 6 74 53 98 59 84 4 40 11 67 14 89 1 44 51 45 44 51 57 75 19 33 54 24 96 1 30 0 45 47 38 58 78 17 74 14 91 60 32 67 10 72 91 61 45 49 68 67 31 69 96 92 52 9 34 36 16 77 62 55 41 42 88 53 4 15 68 98 73 81 41 36 43 87 48 95 55 62 8 12 30 23 34 59 72 85 38 7 16 13 79 66 98 23 69 89 71 84 79 14 53 10 62 60 44 28 49 43 29 45 75 72 94 5 64 3 27 99 41 10 91 2 94 16 85 75 25 95 15 34 36 90 72 76 20 29 55 18 93 53 69 84 87 16 80 64 48 45 63 53 25 10 44 65 58 59 94 31 41 35 89 42 29 71 69 61 63 44 74 33 3 65 47 90 52 38 9 13 91 4 45 26 39 94 68 93 56 31 41 59 32 17 6 85 74 19 58 93 9 92 31 90 69 2 87 11 67 94 53 66 30 15 41 59 51 45 7 59 76 14 15 51 3 88 17 2 42 39 98 84 65 54 48 9 56 74 68 5 1 24 13 55 34 94 50 28 8 14 93 64 52 92 62 9 51 38 31 74 73 24 59 33 65 7 75 32 30 93 48 17 33 67 7 5 0 69 54 76 52 1 87 99 73 50 25 16 13 20 41 77 62 54 0 33 23 75 50 4 29 18 94 14 8 38 48 53 84 13 12 91 83 69 78 55 47 26 30 65 70 51 1 22 53 86 46 89 99 79 20 24 64 18 92 82 0 68 57 33 61 12 83 22 47 21 38 57 41 63 61 95 79 7 52 87 71 14 40 45 92 73 48 42 0 26 94 5 90 98 47 85 52 19 44 48 59 88 93 81 7 16 63 1 45 84 11 24 78 27 62 77 37 34 2 6 3 56 48 47 12 58 76 89 78 30 75 20 91 39 97 69 28 96 64 32 61 67 62 25 53 56 97 42 34 24 64 95 17 35 7 79 68 30 74 54 78 3 88 66 18 38 90 63 45 80 89 76 39 57 71 25 79 6 3 28 94 34 82 18 95 42 33 96 36 27 83 66 20 87 59 86 21 14 61 7 23 56 5 33 91 0 1 97 65 82 95 72 18 26 35 47 69 86 65 41 97 40 2 73 68 34 3 88 71 79 70 95 48 62 1 50 77 13 67 20 15 55 98 16 93 30 24 39 11 56 13 3 14 83 76 58 60 73 81 63 88 92 74 96 51 43 77 4 12 43 46 53 34 37 50 60 56 96 98 10 65 38 40 24 80 77 73 23 67 84 64 13 5 19 85 1 58 41 15 44 57 22 2 66 80 94 71 40 55 89 79 0 56 81 23 30 24 0 29 94 4 68 81 2 20 95 43 49 40 37 30 96 19 23 42 26 85 61 17 12 72 88 64 26 61 32 68 80 24 31 67 49 72 15 88 98 50 73 55 86 38 10 87 34 52 29 63 76 61 36 54 10 63 56 75 67 29 11 9 41 4 43 83 88 45 93 74 72 70 94 60 98 44 99 39 5 23 53 69 68 60 83 81 72 1 97 20 43 96 91 11 32 51 7 8 86 25 62 36 39 20 5 52 59 6 74 95 2 83 44 43 66 96 55 79 42 37 34 32 19 0 90 84 8 65 35 78 57 83 4 82 36 3 29 74 60 90 86 47 53 26 10 52 51 40 32 6 69 32 77 72 44 34 54 82 94 23 1 60 2 11 36 17 52 0 73 31 5 90 24 21 53 42 24 18 44 5 74 19 76 62 34 61 66 4 77 47 92 94 78 39 97 25 91 11 22 23 11 87 83 93 8 7 73 85 84 3 65 16 71 12 44 88 61 54 19 97 72 57 80 59 45 30 55 1 62 39 31 45 34 6 43 68 93 38 57 60 70 32 5 95 92 35 83 66 36 91 76 89 54 36 21 99 28 62 78 73 17 72 96 13 91 79 65 37 81 14 33 86 31 11 25 3 93 37 88 47 4 6 19 87 30 76 22 33 69 64 36 52 60 82 53 39 5 61 67 90 28 6 59 61 75 40 4 65 43 93 41 32 60 89 18 22 11 12 9 0 26 15 78 90 30 8 87 74 70 76 45 43 63 84 25 18 68 92 4 31 66 22 29 71 91 15 50 64 52 1 3 93 25 71 43 45 48 52 4 94 36 34 47 74 97 12 27 64 14 80 41 17 21 32 88 76 62 68 24 0 97 43 37 3 79 65 25 52 28 20 29 18 90 89 48 35 66 19 53 82 57 98 86 69 24 55 74 49 12 35 68 50 70 38 75 82 56 73 5 89 90 10 15 14 95 98 86 47 87 81 62 51 3 79 10 60 39 61 9 77 36 50 89 49 88 63 95 1 15 69 72 71 51 33 23 12 35 97 34 99 4 32 36 88 80 5 17 3 56 1 44 19 47 98 26 55 56 75 5 74 4 86 60 67 68 21 45 40 17 2 43 39 20 88 33 24 70 58 13 98 34 28 86 65 80 82 23 98 91 0 61 62 43 51 49 39 10 58 1 11 8 83 17 97 31 7 96 2 18 26 15 86 34 76 61 75 93 68 3 83 63 37 85 8 74 11 51 32 14 23 25 33 24 86 75 63 73 97 37 47 76 72 34 81 27 93 91 70 20 98 11 94 64 28 6 70 86 59 78 95 47 18 64 40 68 49 55 20 12 53 60 76 35 83 50 32 73 91 46 28 31 21 92 97 89 14 82 51 1 62 43 58 90 18 24 56 79 54 35 48 29 39 45 86 66 62 74 81 27 23 28 92 66 86 29 98 95 14 35 11 13 69 70 64 79 51 80 87 96 85 69 15 37 95 29 6 45 20 17 36 62 42 1 77 59 25 44 72 35 31 70 73 86 89 97 81 88 82 99 13 53 87 2 29 47 36 94 48 95 65 96 42 92 61 60 86 33 83 52 12 32 4 52 54 24 28 77 58 80 16 62 82 59 6 66 63 72 91 41 29 36 22 68 0 31 38 58 51 77 26 80 5 90 30 20 33 14 54 53 0 76 74 63 84 15 45 73 41 29 69 28 31 47 97 58 69 7 86 40 57 45 1 11 84 54 29 9 95 93 88 12 5 79 76 77 93 7 60 75 12 49 64 20 46 10 3 23 76 42 47 9 22 6 34 87 41 37 66 45 48 9 53 64 37 83 89 43 91 30 36 39 22 69 79 42 31 28 55 40 54 7 24 44 84 46 81 75 15 89 31 11 13 12 5 10 94 80 22 68 3 27 60 42 65 58 40 82 17 92 73 16 40 98 33 41 79 72 2 77 86 14 32 85 74 50 11 49 62 56 9 69 20 12 19 60 95 72 61 54 92 10 0 1 84 99 88 62 13 18 86 89 59 60 29 78 55 98 27 91 87 58 37 49 43 76 14 3 65 13 2 92 20 6 73 5 96 53 82 95 99 15 83 80 26 11 51 71 56 58 95 59 84 46 54 94 8 7 49 62 83 47 92 32 31 65 48 44 57 25 20 5 3 26 90 14 61 16 44 4 0 49 1 52 82 54 60 77 86 43 87 6 36 73 25 31 32 25 37 18 63 60 65 35 24 34 52 94 12 77 47 99 83 2 30 74 58 38 17 75 56 77 88 70 22 39 4 14 86 99 50 5 79 2 78 16 34 46 83 58 13 71 74 21 76 66 25 15 99 79 68 59 95 82 22 53 0 70 85 73 67 36 10 66 6 32 1 51 52 40 4 29 49 64 26 18 56 28 9 7 99 20 2 74 71 39 81 94 55 75 16 52 45 35 66 11 42 68 76 37 34 0 41 86 19 59 7 46 49 30 88 74 80 24 50 29 96 78 67 61 26 45 96 11 99 44 87 95 32 77 64 8 31 80 4 34 24 91 90 16 60 13 29 63 67 59 15 55 0 52 54 58 45 62 66 85 91 19 32 16 92 93 59 8 22 2 98 33 31 17 84 28 49 63 81 69 30 45 46 90 26 4 76 94 93 24 15 16 18 86 62 2 98 89 44 67 32 35 11 1 38 86 36 70 24 95 59 94 71 99 40 48 64 91 25 57 29 76 68 88 58 45 81 50 20 68 85 91 49 38 9 27 0 58 8 10 59 1 88 19 89 23 29 61 99 12 74 50 41 83 4 33 34 88 23 14 89 39 98 75 37 26 73 80 71 44 52 53 48 84 85 47 35 98 73 9 61 4 71 91 58 65 40 63 36 86 12 30 69 46 2 6 17 23 32 74 84 87 59 58 65 30 53 7 98 48 71 28 1 77 56 36 88 52 64 89 90 37 94 26 39 25 75 32 48 6 49 7 74 50 62 68 51 72 12 10 94 37 97 69 91 73 9 67 18 1 51 96 71 44 0 97 52 1 77 11 90 9 15 76 24 68 6 57 40 98 47 31 94 82 49 48 31 26 77 14 94 93 27 2 82 11 83 85 9 8 90 69 4 16 22 5 62 29 57 30 59 46 82 13 53 71 58 67 2 28 73 52 30 97 12 95 34 51 32 38 62 81 5 15 74 82 10 58 84 67 92 5 66 25 83 90 76 21 26 69 39 63 42 11 53 23 61 80 99 48 8 13 49 63 83 26 48 50 53 43 1 39 95 60 99 96 7 35 94 10 24 44 65 31 46 87 17 72 71 81 35 56 4 99 59 96 90 37 23 86 34 73 18 19 78 41 10 43 92 80 29 7 37 40 70 72 10 85 74 76 36 9 13 73 82 4 65 49 77 42 75 24 84 78 39 29 6 94 59 38 99 55 8 66 85 14 43 25 92 67 49 33 87 39 44 9 61 24 90 75 45 35 78 56 24 53 38 34 92 55 20 44 90 33 83 54 95 71 87 13 40 43 85 88 68 32 80 59 34 22 18 9 12 15 55 85 60 37 64 92 35 39 26 90 50 52 67 58 87 8 90 96 40 14 61 34 33 80 22 38 59 94 3 6 4 0 71 25 1 20 30 57 48 31 10 50 14 40 48 83 85 80 29 60 2 92 59 86 99 57 46 7 89 66 75 98 6 45 97 51 13 17 0 57 5 29 68 52 11 59 78 63 94 88 89 35 54 74 18 2 28 65 86 1 30 57 46 44 86 62 43 89 81 34 13 32 51 9 6 35 29 52 84 8 88 26 21 17 75 85 14 87 26 22 30 65 78 98 6 60 42 99 19 71 11 68 27 48 52 62 51 1 54 37 74 76 69 37 49 61 20 91 14 31 11 54 40 67 71 15 73 64 85 80 62 5 10 3 51 7 63 90 54 46 17 16 5 4 56 33 39 41 8 87 80 14 77 26 47 70 15 48 6 10 76 96 95 0 42 56 3 87 92 18 60 51 7 38 4 91 41 33 80 43 66 61 32 57 84 10 8 64 76 78 17 55 74 68 47 29 46 84 49 58 93 52 26 32 11 33 24 42 98 27 43 14 19 27 93 16 23 32 74 73 67 68 38 2 22 76 6 12 94 15 77 64 62 34 3 37 Some thoughts about design decision I made and why I made them. Let me know if you think I should have made them different and why:
- using the 'factory' method Create: I wanted the list of numbers inside the BingoCard to be const, but that disallows to read it from std::cin in the constructor. Alternatively, I could remove the const, and put the Create-code inside the constructor.
- 'hit' array as a member: originally, I modified the numbers on the bingo card to -1 to declare them 'drawn', but that felt poor. The BingoCard should not lose information by getting its numbers overwritten. It worked with the -1 though.
- min/max calculation: I considered using stuff from <algorithm>, but I need more than the min/max values themselves; I also need their indexes. I don't see how I could use them at all.