aboutsummaryrefslogtreecommitdiffstats
path: root/src/16/main.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/16/main.zig')
-rw-r--r--src/16/main.zig179
1 files changed, 179 insertions, 0 deletions
diff --git a/src/16/main.zig b/src/16/main.zig
new file mode 100644
index 0000000..1b45177
--- /dev/null
+++ b/src/16/main.zig
@@ -0,0 +1,179 @@
+const std = @import("std");
+const aoc = @import("aoc");
+
+const Range = struct { min: u32, max: u32 };
+const FieldRule = struct { name: []const u8, r1: Range, r2: Range };
+
+fn assert(comptime T: type, part: ?T) !T {
+ if (part == null) return aoc.Error.InvalidInput;
+ return part.?;
+}
+
+fn parseRange(str: []const u8) !Range {
+ const sep = try assert(usize, std.mem.indexOfScalar(u8, str, '-'));
+ if (sep == str.len - 1) return aoc.Error.InvalidInput;
+ return Range{
+ .min = try std.fmt.parseInt(u32, str[0..sep], 10),
+ .max = try std.fmt.parseInt(u32, str[sep + 1 ..], 10),
+ };
+}
+
+fn parseRules(rules: *std.ArrayList(FieldRule), str: []const u8) !void {
+ var lineit = std.mem.tokenize(u8, str, "\n");
+ while (lineit.next()) |line| {
+ const sep = try assert(usize, std.mem.indexOf(u8, line, ": "));
+ if (sep == line.len - 1) return aoc.Error.InvalidInput;
+ const name = line[0..sep];
+ var rangepart = line[sep + 2 ..];
+ var spaceit = std.mem.tokenize(u8, rangepart, " ");
+ const r1 = try parseRange(try assert([]const u8, spaceit.next()));
+ _ = spaceit.next();
+ const r2 = try parseRange(try assert([]const u8, spaceit.next()));
+ try rules.append(FieldRule{ .name = name, .r1 = r1, .r2 = r2 });
+ }
+}
+
+fn parseVals(vals: *std.ArrayList(u32), str: []const u8) !void {
+ var lineit = std.mem.tokenize(u8, str, "\n");
+ while (lineit.next()) |line| {
+ var partit = std.mem.tokenize(u8, line, ",");
+ while (partit.next()) |part| {
+ try vals.append(try std.fmt.parseInt(u32, part, 10));
+ }
+ }
+}
+
+fn matchesRule(rule: FieldRule, v: u32) bool {
+ return (v >= rule.r1.min and v <= rule.r1.max or v >= rule.r2.min and v <= rule.r2.max);
+}
+
+fn hasRule(rules: []FieldRule, v: u32) bool {
+ for (rules) |r| {
+ if (matchesRule(r, v)) return true;
+ }
+ return false;
+}
+
+fn printCandidates(candidates: []u1, rulecount: usize, remove: usize) void {
+ var i: u32 = 0;
+ while (i < rulecount) : (i += 1) {
+ for (candidates[i * rulecount .. (i + 1) * rulecount]) |c| {
+ aoc.debugfmt("{} ", .{c});
+ }
+ if (i == remove) aoc.debugfmt(" <<<", .{});
+ aoc.debugfmt("\n", .{});
+ }
+}
+
+fn part1(allocator: std.mem.Allocator, input: []u8, args: [][]u8) !?[]u8 {
+ _ = args;
+
+ var answer: u32 = 0;
+
+ var rules = std.ArrayList(FieldRule).init(allocator);
+ defer rules.deinit();
+
+ var othervals = std.ArrayList(u32).init(allocator);
+ defer othervals.deinit();
+
+ var secit = std.mem.split(u8, input, "\n\n");
+ try parseRules(&rules, try assert([]const u8, secit.next()));
+ _ = secit.next();
+ try parseVals(&othervals, (try assert([]const u8, secit.next()))[16..]);
+
+ for (othervals.items) |v| {
+ if (!hasRule(rules.items, v)) answer += v;
+ }
+
+ return try std.fmt.allocPrint(allocator, "{}", .{answer});
+}
+
+fn part2(allocator: std.mem.Allocator, input: []u8, args: [][]u8) !?[]u8 {
+ _ = args;
+
+ var rules = std.ArrayList(FieldRule).init(allocator);
+ defer rules.deinit();
+
+ var ownvals = std.ArrayList(u32).init(allocator);
+ defer ownvals.deinit();
+
+ var othervals = std.ArrayList(u32).init(allocator);
+ defer othervals.deinit();
+
+ var secit = std.mem.split(u8, input, "\n\n");
+ try parseRules(&rules, try assert([]const u8, secit.next()));
+ try parseVals(&ownvals, (try assert([]const u8, secit.next()))[13..]);
+ try parseVals(&othervals, (try assert([]const u8, secit.next()))[16..]);
+
+ const rulecount = rules.items.len;
+
+ {
+ var index: u32 = 0;
+ while (index < othervals.items.len) {
+ var i: u32 = 0;
+ while (i < rulecount) : (i += 1) {
+ if (!hasRule(rules.items, othervals.items[index + i]))
+ break;
+ }
+
+ if (i == rulecount) {
+ index += @intCast(u32, rulecount);
+ } else {
+ if (aoc.debug)
+ aoc.debugfmt("REMOVE: ", .{});
+ i = 0;
+ while (i < rulecount) : (i += 1) {
+ if (aoc.debug)
+ aoc.debugfmt("{} ", .{othervals.items[index]});
+ _ = othervals.orderedRemove(index);
+ }
+ if (aoc.debug)
+ aoc.debugfmt("\n", .{});
+ }
+ }
+ }
+
+ var candidates = try allocator.alloc(u1, rulecount * rulecount);
+ defer allocator.free(candidates);
+ std.mem.set(u1, candidates, 1);
+
+ if (aoc.debug)
+ aoc.debugfmt("{}\n", .{othervals.items.len});
+ {
+ var index: u32 = 0;
+ while (index < othervals.items.len) : (index += 1) {
+ const ri = index % rulecount;
+ const v = othervals.items[index];
+ for (rules.items) |r, rri| {
+ if (!matchesRule(r, v)) {
+ candidates[ri * rulecount + rri] = 0;
+ }
+ }
+ }
+ }
+
+ var answer: u64 = 1;
+ {
+ var index: u32 = 0;
+ while (index < rulecount * rulecount) : (index += 1) {
+ var ri = index % rulecount;
+ const cc = candidates[ri * rulecount .. (ri + 1) * rulecount];
+ if (std.mem.count(u1, cc, ([_]u1{1})[0..]) == 1) {
+ const field = std.mem.indexOfScalar(u1, cc, 1).?;
+ if (std.mem.indexOf(u8, rules.items[field].name, "departure") != null)
+ answer *= ownvals.items[ri];
+ for (ownvals.items) |_, ii| {
+ candidates[ii * rulecount + field] = 0;
+ }
+ if (aoc.debug) {
+ printCandidates(candidates, rulecount, ri);
+ aoc.debugfmt("\n", .{});
+ }
+ }
+ }
+ }
+
+ return try std.fmt.allocPrint(allocator, "{}", .{answer});
+}
+
+pub const main = aoc.main(part1, part2, .{ "25972", "622670335901" });