Cleanup 2021 day 8 puzzles
This commit is contained in:
@@ -7,17 +7,74 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
using Segments = std::string;
|
||||||
|
using Segment = char;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief If only one segment is lit return that segment, otherwise return '\0'
|
||||||
|
* \param segments Segments lit
|
||||||
|
* \return Lit segment if only one or '\0' othherwise.
|
||||||
|
*/
|
||||||
|
auto unique_segment(Segments const& segments) -> Segment
|
||||||
|
{
|
||||||
|
if (segments.size() == 1) {
|
||||||
|
return segments[0];
|
||||||
|
}
|
||||||
|
return '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Return unique segment lit when \a remove & \a rest are removed from \a segments
|
||||||
|
* \tparam Args Types of \a rest
|
||||||
|
* \param segments Segments initially lit
|
||||||
|
* \param remove Segment to remove from \a segments
|
||||||
|
* \param rest Any more segments to remove
|
||||||
|
* \return Unique lit segment or '\0' if there isn't one
|
||||||
|
*/
|
||||||
|
template<typename... Args>
|
||||||
|
auto unique_segment(Segments const& segments, Segment remove, Args... rest) -> Segment;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Return unique segment lit when \a remove & \a rest are removed from \a segments
|
||||||
|
* \tparam Args Types of \a rest
|
||||||
|
* \param segments Segments initially lit
|
||||||
|
* \param remove Segment to remove from \a segments
|
||||||
|
* \param rest Any more segments to remove
|
||||||
|
* \return Unique lit segment or '\0' if there isn't one
|
||||||
|
*/
|
||||||
|
template<typename... Args>
|
||||||
|
auto unique_segment(Segments const& segments, Segments const& remove, Args... rest) -> Segment
|
||||||
|
{
|
||||||
|
std::string temp;
|
||||||
|
std::set_difference(segments.begin(), segments.end(), remove.begin(), remove.end(),
|
||||||
|
std::back_inserter(temp));
|
||||||
|
return unique_segment(temp, rest...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
auto unique_segment(Segments const& segments, Segment remove, Args... rest) -> Segment
|
||||||
|
{
|
||||||
|
std::string temp;
|
||||||
|
std::set_difference(segments.begin(), segments.end(), &remove, &remove + 1,
|
||||||
|
std::back_inserter(temp));
|
||||||
|
return unique_segment(temp, rest...);
|
||||||
|
}
|
||||||
|
|
||||||
auto main() -> int
|
auto main() -> int
|
||||||
{
|
{
|
||||||
std::string line;
|
std::string line;
|
||||||
unsigned total{0};
|
unsigned total{0};
|
||||||
|
|
||||||
while (std::getline(std::cin, line)) {
|
while (std::getline(std::cin, line)) {
|
||||||
|
/* We want to identify the digits 1, 4, 7, 8 - which is easy as they're a unique number of lit
|
||||||
|
* segment2s. We also want to make use of 0, 6, and 9 which all have six segments lit - but
|
||||||
|
* we don't know which one matches which - so we keep them in a vector.
|
||||||
|
*/
|
||||||
std::vector<std::string> six_segments;
|
std::vector<std::string> six_segments;
|
||||||
std::string one;
|
Segments one;
|
||||||
std::string four;
|
Segments four;
|
||||||
std::string seven;
|
Segments seven;
|
||||||
std::string eight;
|
Segments eight;
|
||||||
auto it{line.begin()};
|
auto it{line.begin()};
|
||||||
for (; *it != '|'; ++it) {
|
for (; *it != '|'; ++it) {
|
||||||
if (*it == ' ') {
|
if (*it == ' ') {
|
||||||
@@ -49,64 +106,78 @@ auto main() -> int
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now decode: */
|
/* Now decode: Each of these contains the character that maps to the given variable name.
|
||||||
char a{'.'}, b{'.'}, c{'.'}, d{'.'}, e{'.'}, f{'.'}, g{'.'};
|
* aa
|
||||||
std::string temp;
|
* b c
|
||||||
std::set_difference(seven.begin(), seven.end(), one.begin(), one.end(),
|
* b c
|
||||||
std::back_inserter(temp));
|
* dd
|
||||||
a = temp[0];
|
* e f
|
||||||
std::string union47;
|
* e f
|
||||||
std::set_union(seven.begin(), seven.end(), four.begin(), four.end(),
|
* gg
|
||||||
std::back_inserter(union47));
|
*/
|
||||||
for (auto segment : six_segments) {
|
// Segment a{'\0'};
|
||||||
temp.clear();
|
Segment b{'\0'};
|
||||||
std::set_difference(segment.begin(), segment.end(), union47.begin(), union47.end(),
|
// Segment c{'\0'};
|
||||||
std::back_inserter(temp));
|
// Segment d{'\0'};
|
||||||
if (temp.size() == 1) {
|
Segment e{'\0'};
|
||||||
g = temp[0];
|
Segment f{'\0'};
|
||||||
temp.clear();
|
Segment g{'\0'};
|
||||||
std::set_difference(eight.begin(), eight.end(), segment.begin(), segment.end(),
|
|
||||||
std::back_inserter(temp));
|
/* a is easy as it's the element lit in 7 but not in 1. */
|
||||||
e = temp[0];
|
Segment a{unique_segment(seven, one)};
|
||||||
|
|
||||||
|
/* The digit 9 is the only six segment digit which has one segment lit when we remove the
|
||||||
|
* segments lit in 4 and 7. The remaining lit segment is g. (0 and 6 will both have e and g
|
||||||
|
* lit in this case).
|
||||||
|
*
|
||||||
|
* We can then detect e because it is the element lit in 8 which is not lit in 9.
|
||||||
|
*/
|
||||||
|
for (auto const& segments : six_segments) {
|
||||||
|
g = unique_segment(segments, four, seven);
|
||||||
|
if (g != '\0') {
|
||||||
|
e = unique_segment(eight, segments); // NOLINT(readability-suspicious-call-argument)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::string union7ge{seven + g + e};
|
|
||||||
std::sort(union7ge.begin(), union7ge.end());
|
/* The digit 0 is the only six segment digit which has one segment lit which isn't in the digit
|
||||||
for (auto segment : six_segments) {
|
* 7 or is e or g. (6 and 9 have two segments in this case). This lit segment is b.
|
||||||
temp.clear();
|
*/
|
||||||
std::set_difference(segment.begin(), segment.end(), union7ge.begin(), union7ge.end(),
|
for (auto const& segment : six_segments) {
|
||||||
std::back_inserter(temp));
|
b = unique_segment(segment, seven, g, e);
|
||||||
if (temp.size() == 1) {
|
if (b != '\0') {
|
||||||
b = temp[0];
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string union1b{one + b};
|
/* Segment d is the remaining segment from 4 when 1 and b have been removed. */
|
||||||
std::sort(union1b.begin(), union1b.end());
|
Segment d{unique_segment(four, one, b)};
|
||||||
temp.clear();
|
|
||||||
std::set_difference(four.begin(), four.end(), union1b.begin(), union1b.end(),
|
|
||||||
std::back_inserter(temp));
|
|
||||||
d = temp[0];
|
|
||||||
|
|
||||||
std::string unionabdeg{a, b, d, e, g};
|
/* 6 is the six-segment digit with a, b, d, e, and g lit. (0 doesn't have d lit, 9 doesn't
|
||||||
std::sort(unionabdeg.begin(), unionabdeg.end());
|
* have e lit. The remaining segment in 6 is f.
|
||||||
for (auto segment : six_segments) {
|
*/
|
||||||
temp.clear();
|
for (auto const& segment : six_segments) {
|
||||||
std::set_difference(segment.begin(), segment.end(), unionabdeg.begin(), unionabdeg.end(),
|
f = unique_segment(segment, a, b, d, e, g);
|
||||||
std::back_inserter(temp));
|
if (f != '\0') {
|
||||||
if (temp.size() == 1) {
|
break;
|
||||||
f = temp[0];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
temp.clear();
|
/* And finally c is the segment in 1 which isn't f. */
|
||||||
std::string unionf{f};
|
Segment c{unique_segment(one, f)};
|
||||||
std::set_difference(one.begin(), one.end(), unionf.begin(), unionf.end(),
|
|
||||||
std::back_inserter(temp));
|
|
||||||
c = temp[0];
|
|
||||||
|
|
||||||
std::array<std::string, 10> nums{
|
/* Check everything worked (or at least found a result). */
|
||||||
|
assert(a != '\0');
|
||||||
|
assert(b != '\0');
|
||||||
|
assert(c != '\0');
|
||||||
|
assert(d != '\0');
|
||||||
|
assert(e != '\0');
|
||||||
|
assert(f != '\0');
|
||||||
|
assert(g != '\0');
|
||||||
|
|
||||||
|
/* nums is an array of digits containing the segments which make up the display for that digit.
|
||||||
|
*/
|
||||||
|
std::array<Segments, 10> nums{
|
||||||
std::string{a, b, c, e, f, g}, // 0
|
std::string{a, b, c, e, f, g}, // 0
|
||||||
std::string{c, f}, // 1
|
std::string{c, f}, // 1
|
||||||
std::string{a, c, d, e, g}, // 2
|
std::string{a, c, d, e, g}, // 2
|
||||||
@@ -119,17 +190,17 @@ auto main() -> int
|
|||||||
std::string{a, b, c, d, f, g} // 9
|
std::string{a, b, c, d, f, g} // 9
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Sort the digit lists into alphabetical order so checking becomes easier. */
|
||||||
for (auto& num : nums) {
|
for (auto& num : nums) {
|
||||||
std::sort(num.begin(), num.end());
|
std::sort(num.begin(), num.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto num : nums) {
|
/* Now work out the value for this line. */
|
||||||
std::cout << num << '\n';
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned value{0};
|
unsigned value{0};
|
||||||
for (++it; it != line.end(); it = (it == line.end() ? it : it + 1)) {
|
++it;
|
||||||
|
while (it != line.end()) {
|
||||||
if (*it == ' ') {
|
if (*it == ' ') {
|
||||||
|
++it;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
std::string s;
|
std::string s;
|
||||||
@@ -137,7 +208,8 @@ auto main() -> int
|
|||||||
s += *it++;
|
s += *it++;
|
||||||
}
|
}
|
||||||
std::sort(s.begin(), s.end());
|
std::sort(s.begin(), s.end());
|
||||||
auto num{std::find(nums.begin(), nums.end(), s)};
|
auto num{std::find(nums.begin(), // NOLINT(llvm-qualified-auto,readability-qualified-auto)
|
||||||
|
nums.end(), s)};
|
||||||
assert(num != nums.end());
|
assert(num != nums.end());
|
||||||
value *= 10;
|
value *= 10;
|
||||||
value += num - nums.begin();
|
value += num - nums.begin();
|
||||||
|
Reference in New Issue
Block a user