Line data Source code
1 : #include "AsciiMap.h"
2 : #include "LinewiseInput.h"
3 : #include "PuzzleImpl.h"
4 :
5 : #include <libassert/assert.hpp>
6 :
7 : #include <algorithm>
8 : #include <charconv>
9 : #include <cstdint>
10 : #include <span>
11 : #include <string>
12 :
13 : namespace {
14 :
15 : constexpr size_t numCards = 5u;
16 : using Deck = std::span<char const, numCards>;
17 : using Bid = unsigned short;
18 :
19 0 : static constexpr AsciiMap<unsigned> makeCardValueMapPt1() {
20 0 : AsciiMap<unsigned> map('\0');
21 0 : map['2'] = 0u;
22 0 : map['3'] = 1u;
23 0 : map['4'] = 2u;
24 0 : map['5'] = 3u;
25 0 : map['6'] = 4u;
26 0 : map['7'] = 5u;
27 0 : map['8'] = 6u;
28 0 : map['9'] = 7u;
29 0 : map['T'] = 8u;
30 0 : map['J'] = 9u;
31 0 : map['Q'] = 10u;
32 0 : map['K'] = 11u;
33 0 : map['A'] = 12u;
34 0 :
35 0 : return map;
36 0 : }
37 :
38 0 : static constexpr AsciiMap<unsigned> makeCardValueMapPt2() {
39 0 : AsciiMap<unsigned> map('\0');
40 0 : map['J'] = 0u;
41 0 : map['2'] = 1u;
42 0 : map['3'] = 2u;
43 0 : map['4'] = 3u;
44 0 : map['5'] = 4u;
45 0 : map['6'] = 5u;
46 0 : map['7'] = 6u;
47 0 : map['8'] = 7u;
48 0 : map['9'] = 8u;
49 0 : map['T'] = 9u;
50 0 : map['Q'] = 10u;
51 0 : map['K'] = 11u;
52 0 : map['A'] = 12u;
53 0 :
54 0 : return map;
55 0 : }
56 :
57 : struct Part1 {
58 :
59 : static constexpr auto cardValueMap = makeCardValueMapPt1();
60 :
61 1000 : static unsigned getValue(Deck const &deck) {
62 1000 : std::array<unsigned, 13u> frequency{};
63 5000 : for (char card : deck) {
64 5000 : ++frequency[cardValueMap[card]];
65 5000 : }
66 :
67 1000 : std::partial_sort(frequency.begin(), std::next(frequency.begin(), 2), frequency.end(),
68 13791 : [](unsigned lhs, unsigned rhs) { return lhs > rhs; });
69 :
70 1000 : unsigned const &mostFrequent = frequency[0];
71 1000 : unsigned const &secondMostFrequent = frequency[1];
72 :
73 1000 : unsigned value = 0;
74 1000 : if (mostFrequent == 5u) {
75 1 : value = 6;
76 999 : } else if (mostFrequent == 4u) {
77 96 : value = 5;
78 903 : } else if (mostFrequent + secondMostFrequent == 5u) {
79 101 : value = 4;
80 802 : } else if (mostFrequent == 3u) {
81 175 : value = 3;
82 627 : } else if (mostFrequent + secondMostFrequent == 4u) {
83 178 : value = 2;
84 449 : } else if (mostFrequent == 2u) {
85 256 : value = 1;
86 256 : }
87 :
88 5000 : for (char card : deck) {
89 5000 : value <<= 5u;
90 5000 : value += cardValueMap[card];
91 5000 : }
92 :
93 1000 : return value;
94 1000 : }
95 : };
96 :
97 : struct Part2 {
98 :
99 : static constexpr auto cardValueMap = makeCardValueMapPt2();
100 :
101 1000 : static unsigned getValue(Deck const &deck) {
102 1000 : std::array<unsigned, 13u> frequency{};
103 5000 : for (char card : deck) {
104 5000 : ++frequency[cardValueMap[card]];
105 5000 : }
106 :
107 1000 : unsigned const numJokers = frequency[cardValueMap['J']];
108 1000 : frequency[cardValueMap['J']] = 0;
109 :
110 1000 : std::partial_sort(frequency.begin(), std::next(frequency.begin(), 2), frequency.end(),
111 13946 : [](unsigned lhs, unsigned rhs) { return lhs > rhs; });
112 :
113 1000 : unsigned const &mostFrequent = frequency[0];
114 1000 : unsigned const &secondMostFrequent = frequency[1];
115 :
116 1000 : unsigned value = 0;
117 1000 : if (mostFrequent + numJokers == 5u) {
118 30 : value = 6;
119 970 : } else if (mostFrequent + numJokers == 4u) {
120 160 : value = 5;
121 810 : } else if (mostFrequent + secondMostFrequent + numJokers == 5u) {
122 119 : value = 4;
123 691 : } else if (mostFrequent + numJokers == 3u) {
124 235 : value = 3;
125 456 : } else if (mostFrequent + secondMostFrequent + numJokers == 4u) {
126 123 : value = 2;
127 333 : } else if (mostFrequent + numJokers == 2u) {
128 217 : value = 1;
129 217 : }
130 :
131 5000 : for (char card : deck) {
132 5000 : value <<= 5u;
133 5000 : value += cardValueMap[card];
134 5000 : }
135 :
136 1000 : return value;
137 1000 : }
138 : };
139 :
140 : template <typename Part> struct Game {
141 2000 : Game(std::string_view const s) : value(Part::getValue(Deck{s.begin(), 5u})) {
142 2000 : [[maybe_unused]] std::from_chars_result result =
143 2000 : std::from_chars(std::next(s.begin(), 6), s.end(), bid);
144 2000 : DEBUG_ASSERT(result.ec == std::errc());
145 2000 : }
146 : unsigned value = 0;
147 : Bid bid = 0;
148 : };
149 :
150 2 : template <typename Part> size_t run(std::string_view const input) {
151 2 : LinewiseInput const lines(input);
152 :
153 2 : std::vector<Game<Part>> games(lines.begin(), lines.end());
154 :
155 2 : std::sort(games.begin(), games.end(),
156 24008 : [](auto const &lhs, auto const &rhs) { return lhs.value < rhs.value; });
157 :
158 2 : uint64_t rank = 1u;
159 2 : uint64_t sum = 0u;
160 2000 : for (auto const &game : games) {
161 2000 : sum += rank++ * game.bid;
162 2000 : }
163 :
164 2 : return sum;
165 2 : }
166 :
167 : } // namespace
168 :
169 1 : template <> std::string solvePart1<2023, 7>(std::string_view const input) {
170 1 : return std::to_string(run<Part1>(input));
171 1 : }
172 :
173 1 : template <> std::string solvePart2<2023, 7>(std::string_view const input) {
174 1 : return std::to_string(run<Part2>(input));
175 1 : }
|