aboutsummaryrefslogtreecommitdiffstats
path: root/day04/solution.zig
diff options
context:
space:
mode:
Diffstat (limited to 'day04/solution.zig')
-rw-r--r--day04/solution.zig126
1 files changed, 126 insertions, 0 deletions
diff --git a/day04/solution.zig b/day04/solution.zig
new file mode 100644
index 0000000..081277a
--- /dev/null
+++ b/day04/solution.zig
@@ -0,0 +1,126 @@
1const std = @import("std");
2const print = std.debug.print;
3const assert = std.debug.assert;
4const ArrayList = std.ArrayList;
5const mem = std.mem;
6
7const fin = mem.trim(u8, @embedFile("./input.txt"), &std.ascii.whitespace);
8var gpa = std.heap.GeneralPurposeAllocator(.{}){};
9const allocator = gpa.allocator();
10const u32HashSet = std.ArrayHashMap(u32, void, u32HashSetCtx, false);
11
12const u32HashSetCtx = struct {
13 pub fn hash(self: @This(), K: u32) u32 {
14 _ = self;
15 return K;
16 }
17
18 pub fn eql(self: @This(), K1: u32, K2: u32, s: usize) bool {
19 _ = s;
20 _ = self;
21 return K1 == K2;
22 }
23};
24
25const Card = struct {
26 var cardId: u32 = 1;
27 id: u32,
28 winning: u32HashSet,
29 owned: u32HashSet,
30};
31
32fn parseCard(text: []const u8) !Card {
33 var result = Card{
34 .id = Card.cardId,
35 .winning = u32HashSet.init(allocator),
36 .owned = u32HashSet.init(allocator),
37 };
38 Card.cardId += 1;
39
40 var prefix = mem.splitScalar(u8, text, ':');
41 _ = prefix.next(); // ignore 'Card ##' prefix
42 const postfix = prefix.next() orelse unreachable;
43
44 var allNumbers = mem.splitScalar(u8, postfix, '|');
45
46 var winningText = mem.splitScalar(u8, allNumbers.next() orelse unreachable, ' ');
47 var ownedText = mem.splitScalar(u8, allNumbers.next() orelse unreachable, ' ');
48 // split produces some empty strings that must be ignored later
49
50 while (winningText.next()) |numText| {
51 const num = std.fmt.parseInt(u32, numText, 10) catch continue;
52 try result.winning.put(num, undefined);
53 }
54 while (ownedText.next()) |numText| {
55 const num = std.fmt.parseInt(u32, numText, 10) catch continue;
56 try result.owned.put(num, undefined);
57 }
58
59 return result;
60}
61
62fn matchesPerCard(cards: ArrayList(Card)) ArrayList(u64) {
63 var res = ArrayList(u64).init(allocator);
64
65 for (cards.items) |card| {
66 var n: u64 = 0;
67
68 for (card.winning.keys()) |win| {
69 if (card.owned.contains(win)) {
70 n += 1;
71 }
72 }
73 res.append(n) catch unreachable;
74 }
75
76 return res;
77}
78
79pub fn part1(cards: ArrayList(Card)) void {
80 var ans: u64 = 0;
81 const matches = matchesPerCard(cards);
82 defer matches.deinit();
83
84 for (matches.items) |nMatches| {
85 if (nMatches > 0) {
86 ans += std.math.pow(u64, 2, nMatches - 1);
87 }
88 }
89
90 print("{d}\n", .{ans});
91}
92
93pub fn part2(cards: ArrayList(Card)) void {
94 var ans: u64 = 0;
95 var matches = matchesPerCard(cards);
96 var copies = ArrayList(u64).init(allocator);
97 defer {
98 matches.deinit();
99 copies.deinit();
100 }
101 copies.resize(matches.items.len) catch unreachable;
102 @memset(copies.items, 1);
103
104 for (matches.items, copies.items, 0..) |m, c, i| {
105 for (i + 1..i + 1 + m) |j| {
106 copies.items[j] += c;
107 }
108 ans += c;
109 }
110
111 print("{d}\n", .{ans});
112}
113
114pub fn main() !void {
115 var splitLines = mem.splitScalar(u8, fin, '\n');
116 var cards = ArrayList(Card).init(allocator);
117 defer cards.deinit();
118
119 while (splitLines.next()) |line| {
120 const c = try parseCard(line);
121 try cards.append(c);
122 }
123
124 part1(cards);
125 part2(cards);
126}