Line data Source code
1 : #include "IntegerCast.h"
2 : #include "LinewiseInput.h"
3 : #include "PuzzleImpl.h"
4 :
5 : #include <algorithm>
6 : #include <array>
7 : #include <cctype>
8 : #include <numeric>
9 : #include <string>
10 : #include <string_view>
11 :
12 : namespace {
13 :
14 : struct NumberWord {
15 : std::string_view word;
16 : unsigned number;
17 : };
18 :
19 : std::array<NumberWord, 9u> constexpr numberWords = {{{.word = "one", .number = 1u},
20 : {.word = "two", .number = 2u},
21 : {.word = "three", .number = 3u},
22 : {.word = "four", .number = 4u},
23 : {.word = "five", .number = 5u},
24 : {.word = "six", .number = 6u},
25 : {.word = "seven", .number = 7u},
26 : {.word = "eight", .number = 8u},
27 : {.word = "nine", .number = 9u}}};
28 :
29 2000 : template <bool useNumberWords> size_t calibrationValue(std::string_view const line) {
30 2000 : unsigned firstDigit = 0;
31 2000 : auto firstDigitIt =
32 15822 : std::find_if(line.begin(), line.end(), [](char const c) { return std::isdigit(c); });
33 2000 : if (firstDigitIt != line.end())
34 2000 : firstDigit = *firstDigitIt - '0';
35 :
36 2000 : if constexpr (useNumberWords) {
37 9000 : for (NumberWord const &nw : numberWords) {
38 9000 : auto it = std::search(line.begin(), firstDigitIt, nw.word.begin(), nw.word.end());
39 9000 : if (it != firstDigitIt) {
40 559 : firstDigitIt = std::next(it, castToSigned(nw.word.size()));
41 559 : firstDigit = nw.number;
42 559 : }
43 9000 : }
44 1000 : }
45 :
46 2000 : unsigned lastDigit = 0;
47 2000 : auto lastDigitIt =
48 15216 : std::find_if(line.rbegin(), line.rend(), [](char const c) { return std::isdigit(c); });
49 :
50 2000 : if (lastDigitIt != line.rend())
51 2000 : lastDigit = *lastDigitIt - '0';
52 :
53 2000 : if constexpr (useNumberWords) {
54 9000 : for (NumberWord const &nw : numberWords) {
55 9000 : auto it = std::search(line.rbegin(), lastDigitIt, nw.word.rbegin(), nw.word.rend());
56 9000 : if (it != lastDigitIt) {
57 548 : lastDigitIt = std::next(it, castToSigned(nw.word.size()));
58 548 : lastDigit = nw.number;
59 548 : }
60 9000 : }
61 1000 : }
62 :
63 2000 : constexpr unsigned base = 10;
64 2000 : return firstDigit * base + lastDigit;
65 2000 : }
66 : } // namespace
67 :
68 1 : template <> std::string solvePart1<2023, 1>(std::string_view const input) {
69 1 : LinewiseInput const lines(input);
70 :
71 1 : return std::to_string(std::transform_reduce(lines.begin(), lines.end(), size_t(0), std::plus<>(),
72 1 : calibrationValue<false>));
73 1 : }
74 :
75 1 : template <> std::string solvePart2<2023, 1>(std::string_view const input) {
76 1 : LinewiseInput const lines(input);
77 :
78 1 : return std::to_string(std::transform_reduce(lines.begin(), lines.end(), size_t(0), std::plus<>(),
79 1 : calibrationValue<true>));
80 1 : }
|