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