aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOrfeas <38209077+0xfea5@users.noreply.github.com>2023-12-08 01:48:35 +0200
committerOrfeas <38209077+0xfea5@users.noreply.github.com>2025-10-28 23:20:45 +0200
commitd872e4f9f61b2e08dd12cfd8212d1e5abc8a62d2 (patch)
tree67804ffda0a44abd8dccdcf66956e41decf3eb17
parentday6 (diff)
downloadaoc23-d872e4f9f61b2e08dd12cfd8212d1e5abc8a62d2.tar.gz
aoc23-d872e4f9f61b2e08dd12cfd8212d1e5abc8a62d2.zip
day7
-rw-r--r--day07/example.txt5
-rw-r--r--day07/solution.zig215
2 files changed, 220 insertions, 0 deletions
diff --git a/day07/example.txt b/day07/example.txt
new file mode 100644
index 0000000..e3500c3
--- /dev/null
+++ b/day07/example.txt
@@ -0,0 +1,5 @@
132T3K 765
2T55J5 684
3KK677 28
4KTJJT 220
5QQQJA 483
diff --git a/day07/solution.zig b/day07/solution.zig
new file mode 100644
index 0000000..b452dfb
--- /dev/null
+++ b/day07/solution.zig
@@ -0,0 +1,215 @@
1const std = @import("std");
2const print = std.debug.print;
3const assert = std.debug.assert;
4const ArrayList = std.ArrayList;
5const HashMap = std.HashMap;
6const mem = std.mem;
7
8const fin = mem.trim(u8, @embedFile("./input.txt"), &std.ascii.whitespace);
9var gpa = std.heap.GeneralPurposeAllocator(.{}){};
10const allocator = gpa.allocator();
11
12const Combo = enum(u32) {
13 high,
14 pair1,
15 pair2,
16 triple,
17 full,
18 quad,
19 quint,
20};
21
22const Player = struct {
23 bid: u64,
24 hand: [5]u8,
25 combo: Combo,
26
27 fn evalHand(hand: []const u8) Combo {
28 var cardF = [_]u32{0} ** 256;
29
30 for (hand) |c| {
31 cardF[c] += 1;
32 }
33
34 var combo = Combo.high;
35 for (cardF) |f| {
36 switch (f) {
37 0, 1 => {},
38 2 => {
39 combo = switch (combo) {
40 .pair1 => .pair2,
41 .triple => .full,
42 else => .pair1,
43 };
44 },
45 3 => combo = if (combo == Combo.pair1) .full else .triple,
46 4 => combo = .quad,
47 5 => combo = .quint,
48 else => unreachable,
49 }
50 }
51
52 return combo;
53 }
54
55 fn evalHandWithJoker(hand: []const u8) Combo {
56 var cardF = [_]u32{0} ** 256;
57 var cmax: usize = 0;
58
59 for (hand) |c| {
60 cardF[c] += 1;
61 if (c != 'J' and cardF[c] > cardF[cmax]) {
62 cmax = c;
63 }
64 }
65
66 cardF[cmax] += cardF['J'];
67
68 var combo = Combo.high;
69 for (cardF, 0..) |f, c| {
70 if (c == 'J') {
71 continue;
72 }
73 switch (f) {
74 0, 1 => {},
75 2 => {
76 combo = switch (combo) {
77 .pair1 => .pair2,
78 .triple => .full,
79 else => .pair1,
80 };
81 },
82 3 => combo = if (combo == Combo.pair1) .full else .triple,
83 4 => combo = .quad,
84 5 => combo = .quint,
85 else => unreachable,
86 }
87 }
88
89 return combo;
90 }
91
92 pub fn init(hand: []const u8, bid: u64) Player {
93 var res: Player = undefined;
94 res.bid = bid;
95 res.combo = Player.evalHand(hand);
96 mem.copy(u8, &res.hand, hand);
97
98 return res;
99 }
100
101 pub fn initWithJoker(hand: []const u8, bid: u64) Player {
102 var res: Player = undefined;
103 res.bid = bid;
104 res.combo = Player.evalHandWithJoker(hand);
105 mem.copy(u8, &res.hand, hand);
106
107 return res;
108 }
109};
110
111fn cardValue(c: u8) u64 {
112 switch (c) {
113 '2'...'9' => return c - '0',
114 'T' => return 10,
115 'J' => return 11,
116 'Q' => return 12,
117 'K' => return 13,
118 'A' => return 14,
119 else => unreachable,
120 }
121}
122
123fn cmpCard(_: void, lhs: u8, rhs: u8) bool {
124 return cardValue(lhs) < cardValue(rhs);
125}
126
127fn playerCmp(_: void, lhs: Player, rhs: Player) bool {
128 if (lhs.combo != rhs.combo) {
129 return @intFromEnum(lhs.combo) < @intFromEnum(rhs.combo);
130 }
131
132 for (lhs.hand, rhs.hand) |l, r| {
133 if (l != r) {
134 return cmpCard(undefined, l, r);
135 }
136 }
137
138 return false;
139}
140
141fn cardValueWithJoker(c: u8) u64 {
142 switch (c) {
143 '2'...'9' => return c - '0',
144 'T' => return 10,
145 'J' => return 0,
146 'Q' => return 12,
147 'K' => return 13,
148 'A' => return 14,
149 else => unreachable,
150 }
151}
152
153fn cmpCardWithJoker(_: void, lhs: u8, rhs: u8) bool {
154 return cardValueWithJoker(lhs) < cardValueWithJoker(rhs);
155}
156
157fn playerCmpWithJoker(_: void, lhs: Player, rhs: Player) bool {
158 if (lhs.combo != rhs.combo) {
159 return @intFromEnum(lhs.combo) < @intFromEnum(rhs.combo);
160 }
161
162 for (lhs.hand, rhs.hand) |l, r| {
163 if (l != r) {
164 return cmpCardWithJoker(undefined, l, r);
165 }
166 }
167
168 return false;
169}
170
171pub fn part1(players: []Player) void {
172 var ans: u64 = 0;
173
174 mem.sort(Player, players, {}, playerCmp);
175
176 for (players, 1..) |p, rank| {
177 ans += p.bid * rank;
178 }
179
180 print("{d}\n", .{ans});
181}
182
183pub fn part2(players: []Player) void {
184 var ans: u64 = 0;
185
186 mem.sort(Player, players, {}, playerCmpWithJoker);
187
188 for (players, 1..) |p, rank| {
189 ans += p.bid * rank;
190 }
191
192 print("{d}\n", .{ans});
193}
194
195pub fn main() !void {
196 var splitLines = mem.splitScalar(u8, fin, '\n');
197 var players_pt1 = ArrayList(Player).init(allocator);
198 var players_pt2 = ArrayList(Player).init(allocator);
199 defer {
200 players_pt1.deinit();
201 players_pt2.deinit();
202 }
203
204 while (splitLines.next()) |line| {
205 var splitElem = mem.splitScalar(u8, line, ' ');
206 const hand = splitElem.next().?;
207 const bid = try std.fmt.parseInt(u64, splitElem.next().?, 10);
208
209 try players_pt1.append(Player.init(hand, bid));
210 try players_pt2.append(Player.initWithJoker(hand, bid));
211 }
212
213 part1(players_pt1.items);
214 part2(players_pt2.items);
215}