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