diff options
| author | Orfeas <38209077+0xfea5@users.noreply.github.com> | 2023-12-22 00:18:16 +0200 |
|---|---|---|
| committer | Orfeas <38209077+0xfea5@users.noreply.github.com> | 2025-10-28 23:20:45 +0200 |
| commit | aa89ad04dacc7281c81a37199fd67460b8482fba (patch) | |
| tree | 8453453d26efd4da9474d24411ed00ff6d339698 /day19 | |
| parent | day18 (diff) | |
| download | aoc23-main.tar.gz aoc23-main.zip | |
Diffstat (limited to 'day19')
| -rw-r--r-- | day19/example.txt | 17 | ||||
| -rw-r--r-- | day19/solution.zig | 204 |
2 files changed, 221 insertions, 0 deletions
diff --git a/day19/example.txt b/day19/example.txt new file mode 100644 index 0000000..e5b5d64 --- /dev/null +++ b/day19/example.txt | |||
| @@ -0,0 +1,17 @@ | |||
| 1 | px{a<2006:qkq,m>2090:A,rfg} | ||
| 2 | pv{a>1716:R,A} | ||
| 3 | lnx{m>1548:A,A} | ||
| 4 | rfg{s<537:gd,x>2440:R,A} | ||
| 5 | qs{s>3448:A,lnx} | ||
| 6 | qkq{x<1416:A,crn} | ||
| 7 | crn{x>2662:A,R} | ||
| 8 | in{s<1351:px,qqz} | ||
| 9 | qqz{s>2770:qs,m<1801:hdj,R} | ||
| 10 | gd{a>3333:R,R} | ||
| 11 | hdj{m>838:A,pv} | ||
| 12 | |||
| 13 | {x=787,m=2655,a=1222,s=2876} | ||
| 14 | {x=1679,m=44,a=2067,s=496} | ||
| 15 | {x=2036,m=264,a=79,s=2244} | ||
| 16 | {x=2461,m=1339,a=466,s=291} | ||
| 17 | {x=2127,m=1623,a=2188,s=1013} | ||
diff --git a/day19/solution.zig b/day19/solution.zig new file mode 100644 index 0000000..0c4b274 --- /dev/null +++ b/day19/solution.zig | |||
| @@ -0,0 +1,204 @@ | |||
| 1 | const std = @import("std"); | ||
| 2 | const print = std.debug.print; | ||
| 3 | const assert = std.debug.assert; | ||
| 4 | const ArrayList = std.ArrayList; | ||
| 5 | const HashMap = std.HashMap; | ||
| 6 | const mem = std.mem; | ||
| 7 | |||
| 8 | const fin = mem.trim(u8, @embedFile("./input.txt"), &std.ascii.whitespace); | ||
| 9 | var gpa = std.heap.GeneralPurposeAllocator(.{}){}; | ||
| 10 | const allocator = gpa.allocator(); | ||
| 11 | |||
| 12 | const Condition = struct { | ||
| 13 | let: u64, | ||
| 14 | islt: bool, | ||
| 15 | thresh: u64, | ||
| 16 | |||
| 17 | pub fn check(self: @This(), val: u64) bool { | ||
| 18 | return if (self.islt) val < self.thresh else val > self.thresh; | ||
| 19 | } | ||
| 20 | }; | ||
| 21 | |||
| 22 | const Rule = struct { | ||
| 23 | cond: ?Condition, | ||
| 24 | res: []const u8, | ||
| 25 | |||
| 26 | fn parseCondition(s: []const u8) Condition { | ||
| 27 | var splitCond = mem.tokenizeAny(u8, s, "<>"); | ||
| 28 | const let: u64 = switch (splitCond.next().?[0]) { | ||
| 29 | 'x' => 0, | ||
| 30 | 'm' => 1, | ||
| 31 | 'a' => 2, | ||
| 32 | 's' => 3, | ||
| 33 | else => unreachable, | ||
| 34 | }; | ||
| 35 | const islt = mem.count(u8, s, "<") != 0; | ||
| 36 | const thresh = std.fmt.parseInt(u64, splitCond.next().?, 10) catch unreachable; | ||
| 37 | |||
| 38 | return Condition{ | ||
| 39 | .let = let, | ||
| 40 | .islt = islt, | ||
| 41 | .thresh = thresh, | ||
| 42 | }; | ||
| 43 | } | ||
| 44 | |||
| 45 | pub fn parse(s: []const u8) Rule { | ||
| 46 | var splitRule = mem.tokenizeScalar(u8, s, ':'); | ||
| 47 | const first = splitRule.next().?; | ||
| 48 | const second = splitRule.next(); | ||
| 49 | |||
| 50 | return if (second) |resStr| | ||
| 51 | Rule{ | ||
| 52 | .cond = parseCondition(first), | ||
| 53 | .res = resStr, | ||
| 54 | } | ||
| 55 | else | ||
| 56 | Rule{ | ||
| 57 | .cond = null, | ||
| 58 | .res = first, | ||
| 59 | }; | ||
| 60 | } | ||
| 61 | |||
| 62 | pub fn check(self: @This(), ratings: Ratings) ?[]const u8 { | ||
| 63 | if (self.cond) |cond| { | ||
| 64 | return if (cond.check(ratings[cond.let])) self.res else null; | ||
| 65 | } | ||
| 66 | return self.res; | ||
| 67 | } | ||
| 68 | |||
| 69 | pub fn getNext(list: RuleList, ratings: Ratings) []const u8 { | ||
| 70 | for (list) |rule| { | ||
| 71 | const res = rule.check(ratings) orelse continue; | ||
| 72 | |||
| 73 | return res; | ||
| 74 | } | ||
| 75 | |||
| 76 | unreachable; | ||
| 77 | } | ||
| 78 | |||
| 79 | pub fn rangeCombs(rules: RuleGraph, curr: []const u8, ranges: Ranges) u64 { | ||
| 80 | if (mem.eql(u8, curr, "A")) { | ||
| 81 | var res: u64 = 1; | ||
| 82 | for (ranges) |r| { | ||
| 83 | res *= r[1] - r[0] + 1; | ||
| 84 | } | ||
| 85 | return res; | ||
| 86 | } else if (mem.eql(u8, curr, "R")) { | ||
| 87 | return 0; | ||
| 88 | } | ||
| 89 | |||
| 90 | var ans: u64 = 0; | ||
| 91 | var ranges_rej: Ranges = undefined; | ||
| 92 | @memcpy(&ranges_rej, &ranges); | ||
| 93 | |||
| 94 | const rule_list = rules.get(curr).?; | ||
| 95 | for (rule_list) |rule| { | ||
| 96 | if (rule.cond) |cond| { | ||
| 97 | const thresh = cond.thresh; | ||
| 98 | const l = ranges[cond.let][0]; | ||
| 99 | const r = ranges[cond.let][1]; | ||
| 100 | var ranges_suc: Ranges = undefined; | ||
| 101 | @memcpy(&ranges_suc, &ranges_rej); | ||
| 102 | |||
| 103 | if (cond.islt) { | ||
| 104 | ranges_suc[cond.let] = nextRange( | ||
| 105 | ranges_suc[cond.let], | ||
| 106 | .{ l, thresh - 1 }, | ||
| 107 | ); | ||
| 108 | ranges_rej[cond.let] = nextRange( | ||
| 109 | ranges_rej[cond.let], | ||
| 110 | .{ thresh, r }, | ||
| 111 | ); | ||
| 112 | } else { | ||
| 113 | ranges_suc[cond.let] = nextRange( | ||
| 114 | ranges_suc[cond.let], | ||
| 115 | .{ thresh + 1, r }, | ||
| 116 | ); | ||
| 117 | ranges_rej[cond.let] = nextRange( | ||
| 118 | ranges_rej[cond.let], | ||
| 119 | .{ l, thresh }, | ||
| 120 | ); | ||
| 121 | } | ||
| 122 | ans += rangeCombs(rules, rule.res, ranges_suc); | ||
| 123 | } else { | ||
| 124 | ans += rangeCombs(rules, rule.res, ranges_rej); | ||
| 125 | } | ||
| 126 | } | ||
| 127 | |||
| 128 | return ans; | ||
| 129 | } | ||
| 130 | }; | ||
| 131 | |||
| 132 | const Range = [2]u64; | ||
| 133 | const Ranges = [4]Range; | ||
| 134 | const Ratings = []u64; | ||
| 135 | const RuleList = []const Rule; | ||
| 136 | const RuleGraph = std.StringHashMap(RuleList); | ||
| 137 | |||
| 138 | fn nextRange(lhs: Range, rhs: Range) Range { | ||
| 139 | return Range{ | ||
| 140 | @max(lhs[0], rhs[0]), | ||
| 141 | @min(lhs[1], rhs[1]), | ||
| 142 | }; | ||
| 143 | } | ||
| 144 | |||
| 145 | pub fn solve(rules: RuleGraph, parts: []const Ratings) !void { | ||
| 146 | var part1: u64 = 0; | ||
| 147 | for (parts) |ratings| { | ||
| 148 | var curr: []const u8 = "in"; | ||
| 149 | |||
| 150 | const accepted = while (true) { | ||
| 151 | if (mem.eql(u8, curr, "A")) { | ||
| 152 | break true; | ||
| 153 | } else if (mem.eql(u8, curr, "R")) { | ||
| 154 | break false; | ||
| 155 | } | ||
| 156 | curr = Rule.getNext(rules.get(curr).?, ratings); | ||
| 157 | }; | ||
| 158 | |||
| 159 | if (accepted) { | ||
| 160 | for (ratings) |r| { | ||
| 161 | part1 += r; | ||
| 162 | } | ||
| 163 | } | ||
| 164 | } | ||
| 165 | |||
| 166 | print("{d}\n", .{part1}); | ||
| 167 | |||
| 168 | const ranges = [_]Range{Range{ 1, 4000 }} ** 4; | ||
| 169 | const ans = Rule.rangeCombs(rules, "in", ranges); | ||
| 170 | |||
| 171 | print("{d}\n", .{ans}); | ||
| 172 | } | ||
| 173 | |||
| 174 | pub fn main() !void { | ||
| 175 | var segments = mem.tokenizeSequence(u8, fin, "\n\n"); | ||
| 176 | var splitRules = mem.tokenizeScalar(u8, segments.next().?, '\n'); | ||
| 177 | var splitWorkflows = mem.tokenizeScalar(u8, segments.next().?, '\n'); | ||
| 178 | var allRules = RuleGraph.init(allocator); | ||
| 179 | var parts = ArrayList(Ratings).init(allocator); | ||
| 180 | |||
| 181 | while (splitRules.next()) |line| { | ||
| 182 | var list = mem.tokenizeAny(u8, line, "{},"); | ||
| 183 | const id = list.next().?; | ||
| 184 | var rules = ArrayList(Rule).init(allocator); | ||
| 185 | |||
| 186 | while (list.next()) |ruleStr| { | ||
| 187 | try rules.append(Rule.parse(ruleStr)); | ||
| 188 | } | ||
| 189 | try allRules.put(id, rules.items); | ||
| 190 | } | ||
| 191 | |||
| 192 | while (splitWorkflows.next()) |line| { | ||
| 193 | var splitRatings = mem.tokenizeAny(u8, line, "{=,xmas}"); | ||
| 194 | var ratings = ArrayList(u64).init(allocator); | ||
| 195 | |||
| 196 | while (splitRatings.next()) |r| { | ||
| 197 | try ratings.append(try std.fmt.parseInt(u64, r, 10)); | ||
| 198 | } | ||
| 199 | |||
| 200 | try parts.append(ratings.items); | ||
| 201 | } | ||
| 202 | |||
| 203 | try solve(allRules, parts.items); | ||
| 204 | } | ||
