main.zig (5936B)
1const std = @import("std"); 2const aoc = @import("aoc"); 3 4const Range = struct { min: u32, max: u32 }; 5const FieldRule = struct { name: []const u8, r1: Range, r2: Range }; 6 7fn assert(comptime T: type, part: ?T) !T { 8 if (part == null) return aoc.Error.InvalidInput; 9 return part.?; 10} 11 12fn parseRange(str: []const u8) !Range { 13 const sep = try assert(usize, std.mem.indexOfScalar(u8, str, '-')); 14 if (sep == str.len - 1) return aoc.Error.InvalidInput; 15 return Range{ 16 .min = try std.fmt.parseInt(u32, str[0..sep], 10), 17 .max = try std.fmt.parseInt(u32, str[sep + 1 ..], 10), 18 }; 19} 20 21fn parseRules(rules: *std.ArrayList(FieldRule), str: []const u8) !void { 22 var lineit = std.mem.tokenize(u8, str, "\n"); 23 while (lineit.next()) |line| { 24 const sep = try assert(usize, std.mem.indexOf(u8, line, ": ")); 25 if (sep == line.len - 1) return aoc.Error.InvalidInput; 26 const name = line[0..sep]; 27 var rangepart = line[sep + 2 ..]; 28 var spaceit = std.mem.tokenize(u8, rangepart, " "); 29 const r1 = try parseRange(try assert([]const u8, spaceit.next())); 30 _ = spaceit.next(); 31 const r2 = try parseRange(try assert([]const u8, spaceit.next())); 32 try rules.append(FieldRule{ .name = name, .r1 = r1, .r2 = r2 }); 33 } 34} 35 36fn parseVals(vals: *std.ArrayList(u32), str: []const u8) !void { 37 var lineit = std.mem.tokenize(u8, str, "\n"); 38 while (lineit.next()) |line| { 39 var partit = std.mem.tokenize(u8, line, ","); 40 while (partit.next()) |part| { 41 try vals.append(try std.fmt.parseInt(u32, part, 10)); 42 } 43 } 44} 45 46fn matchesRule(rule: FieldRule, v: u32) bool { 47 return (v >= rule.r1.min and v <= rule.r1.max or v >= rule.r2.min and v <= rule.r2.max); 48} 49 50fn hasRule(rules: []FieldRule, v: u32) bool { 51 for (rules) |r| { 52 if (matchesRule(r, v)) return true; 53 } 54 return false; 55} 56 57fn printCandidates(candidates: []u1, rulecount: usize, remove: usize) void { 58 var i: u32 = 0; 59 while (i < rulecount) : (i += 1) { 60 for (candidates[i * rulecount .. (i + 1) * rulecount]) |c| { 61 aoc.debugfmt("{} ", .{c}); 62 } 63 if (i == remove) aoc.debugfmt(" <<<", .{}); 64 aoc.debugfmt("\n", .{}); 65 } 66} 67 68fn part1(allocator: std.mem.Allocator, input: []u8, args: [][]u8) !?[]u8 { 69 _ = args; 70 71 var answer: u32 = 0; 72 73 var rules = std.ArrayList(FieldRule).init(allocator); 74 defer rules.deinit(); 75 76 var othervals = std.ArrayList(u32).init(allocator); 77 defer othervals.deinit(); 78 79 var secit = std.mem.split(u8, input, "\n\n"); 80 try parseRules(&rules, try assert([]const u8, secit.next())); 81 _ = secit.next(); 82 try parseVals(&othervals, (try assert([]const u8, secit.next()))[16..]); 83 84 for (othervals.items) |v| { 85 if (!hasRule(rules.items, v)) answer += v; 86 } 87 88 return try std.fmt.allocPrint(allocator, "{}", .{answer}); 89} 90 91fn part2(allocator: std.mem.Allocator, input: []u8, args: [][]u8) !?[]u8 { 92 _ = args; 93 94 var rules = std.ArrayList(FieldRule).init(allocator); 95 defer rules.deinit(); 96 97 var ownvals = std.ArrayList(u32).init(allocator); 98 defer ownvals.deinit(); 99 100 var othervals = std.ArrayList(u32).init(allocator); 101 defer othervals.deinit(); 102 103 var secit = std.mem.split(u8, input, "\n\n"); 104 try parseRules(&rules, try assert([]const u8, secit.next())); 105 try parseVals(&ownvals, (try assert([]const u8, secit.next()))[13..]); 106 try parseVals(&othervals, (try assert([]const u8, secit.next()))[16..]); 107 108 const rulecount = rules.items.len; 109 110 { 111 var index: u32 = 0; 112 while (index < othervals.items.len) { 113 var i: u32 = 0; 114 while (i < rulecount) : (i += 1) { 115 if (!hasRule(rules.items, othervals.items[index + i])) 116 break; 117 } 118 119 if (i == rulecount) { 120 index += @intCast(u32, rulecount); 121 } else { 122 if (aoc.debug) 123 aoc.debugfmt("REMOVE: ", .{}); 124 i = 0; 125 while (i < rulecount) : (i += 1) { 126 if (aoc.debug) 127 aoc.debugfmt("{} ", .{othervals.items[index]}); 128 _ = othervals.orderedRemove(index); 129 } 130 if (aoc.debug) 131 aoc.debugfmt("\n", .{}); 132 } 133 } 134 } 135 136 var candidates = try allocator.alloc(u1, rulecount * rulecount); 137 defer allocator.free(candidates); 138 std.mem.set(u1, candidates, 1); 139 140 if (aoc.debug) 141 aoc.debugfmt("{}\n", .{othervals.items.len}); 142 { 143 var index: u32 = 0; 144 while (index < othervals.items.len) : (index += 1) { 145 const ri = index % rulecount; 146 const v = othervals.items[index]; 147 for (rules.items) |r, rri| { 148 if (!matchesRule(r, v)) { 149 candidates[ri * rulecount + rri] = 0; 150 } 151 } 152 } 153 } 154 155 var answer: u64 = 1; 156 { 157 var index: u32 = 0; 158 while (index < rulecount * rulecount) : (index += 1) { 159 var ri = index % rulecount; 160 const cc = candidates[ri * rulecount .. (ri + 1) * rulecount]; 161 if (std.mem.count(u1, cc, ([_]u1{1})[0..]) == 1) { 162 const field = std.mem.indexOfScalar(u1, cc, 1).?; 163 if (std.mem.indexOf(u8, rules.items[field].name, "departure") != null) 164 answer *= ownvals.items[ri]; 165 for (ownvals.items) |_, ii| { 166 candidates[ii * rulecount + field] = 0; 167 } 168 if (aoc.debug) { 169 printCandidates(candidates, rulecount, ri); 170 aoc.debugfmt("\n", .{}); 171 } 172 } 173 } 174 } 175 176 return try std.fmt.allocPrint(allocator, "{}", .{answer}); 177} 178 179pub const main = aoc.main(part1, part2, .{ "25972", "622670335901" });