diff options
Diffstat (limited to 'day04/solution.zig')
| -rw-r--r-- | day04/solution.zig | 126 |
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 @@ | |||
| 1 | const std = @import("std"); | ||
| 2 | const print = std.debug.print; | ||
| 3 | const assert = std.debug.assert; | ||
| 4 | const ArrayList = std.ArrayList; | ||
| 5 | const mem = std.mem; | ||
| 6 | |||
| 7 | const fin = mem.trim(u8, @embedFile("./input.txt"), &std.ascii.whitespace); | ||
| 8 | var gpa = std.heap.GeneralPurposeAllocator(.{}){}; | ||
| 9 | const allocator = gpa.allocator(); | ||
| 10 | const u32HashSet = std.ArrayHashMap(u32, void, u32HashSetCtx, false); | ||
| 11 | |||
| 12 | const 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 | |||
| 25 | const Card = struct { | ||
| 26 | var cardId: u32 = 1; | ||
| 27 | id: u32, | ||
| 28 | winning: u32HashSet, | ||
| 29 | owned: u32HashSet, | ||
| 30 | }; | ||
| 31 | |||
| 32 | fn 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 | |||
| 62 | fn 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 | |||
| 79 | pub 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 | |||
| 93 | pub 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 | |||
| 114 | pub 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 | } | ||
