main.zig (6119B)
1const std = @import("std"); 2const aoc = @import("aoc"); 3 4const Rule = union(enum) { 5 c: u8, 6 combos: []const []const usize, 7}; 8 9fn printSlice(slice: []const usize) void { 10 for (slice) |v, i| { 11 if (i > 0) { 12 aoc.debugfmt(" ", .{}); 13 } 14 aoc.debugfmt("{}", .{v}); 15 } 16} 17 18var stacktrace: std.ArrayList(usize) = undefined; 19 20fn checkRule(rules: *std.AutoHashMap(usize, Rule), rid: usize, msg: []const u8, nextstack: *std.ArrayList(usize)) anyerror!bool { 21 if (msg.len == 0) return true; 22 const rule = rules.get(rid) orelse return aoc.Error.InvalidInput; 23 24 if (rule == .c) { 25 if (msg[0] != rule.c) return false; 26 if (msg.len == 1) return (nextstack.items.len == 0); 27 if (nextstack.items.len == 0) return false; 28 29 const next = nextstack.pop(); 30 31 const valid = try checkRule(rules, next, msg[1..], nextstack); 32 if (valid) try stacktrace.append(next); 33 if (valid) return true; 34 35 try nextstack.append(next); 36 } else { 37 for (rule.combos) |ruleseq| { 38 try nextstack.appendSlice(ruleseq[1..]); 39 std.mem.reverse(usize, nextstack.items[nextstack.items.len - (ruleseq.len - 1) ..]); 40 41 const valid = try checkRule(rules, ruleseq[0], msg, nextstack); 42 if (valid) try stacktrace.append(ruleseq[0]); 43 if (valid) return true; 44 45 try nextstack.resize(nextstack.items.len - (ruleseq.len - 1)); 46 } 47 } 48 return false; 49} 50 51fn freeRules(allocator: std.mem.Allocator, rules: *std.AutoHashMap(usize, Rule), ignore: ?[]const usize) void { 52 var mapit = rules.iterator(); 53 while (mapit.next()) |kv| { 54 if (ignore != null and std.mem.indexOfScalar(usize, ignore.?, kv.key_ptr.*) != null) continue; 55 if (kv.value_ptr.* == .combos) { 56 for (kv.value_ptr.combos) |rs| { 57 allocator.free(rs); 58 } 59 allocator.free(kv.value_ptr.combos); 60 } 61 } 62 rules.deinit(); 63} 64 65fn parseRule(allocator: std.mem.Allocator, rules: *std.AutoHashMap(usize, Rule), line: []const u8) !void { 66 const indexsep = try aoc.unwrap(std.mem.indexOf(u8, line, ": ")); 67 const index = try std.fmt.parseInt(usize, line[0..indexsep], 10); 68 69 var chrsep = std.mem.indexOf(u8, line, "\""); 70 if (chrsep != null) { 71 if (chrsep.? == line.len - 1) return aoc.Error.InvalidInput; 72 try rules.put(index, Rule{ .c = line[chrsep.? + 1] }); 73 } else { 74 var vals = std.ArrayList([]usize).init(allocator); 75 errdefer vals.deinit(); 76 77 var ruleit = std.mem.split(u8, line[indexsep + 2 ..], " | "); 78 while (ruleit.next()) |r| { 79 var ruleids = std.ArrayList(usize).init(allocator); 80 errdefer ruleids.deinit(); 81 82 var spaceit = std.mem.tokenize(u8, r, " "); 83 while (spaceit.next()) |word| { 84 try ruleids.append(try std.fmt.parseInt(usize, word, 10)); 85 } 86 87 if (ruleids.items.len == 0) return aoc.Error.InvalidInput; 88 89 try vals.append(ruleids.items); 90 } 91 92 try rules.put(index, Rule{ .combos = vals.items }); 93 } 94} 95 96fn part1(allocator: std.mem.Allocator, input: []u8, args: [][]u8) !?[]u8 { 97 _ = args; 98 99 var rules = std.AutoHashMap(usize, Rule).init(allocator); 100 defer freeRules(allocator, &rules, null); 101 102 var partit = std.mem.split(u8, input, "\n\n"); 103 104 var lineit = std.mem.tokenize(u8, try aoc.unwrap(partit.next()), "\n"); 105 while (lineit.next()) |line| { 106 try parseRule(allocator, &rules, line); 107 } 108 109 var answer: u32 = 0; 110 var nextstack = std.ArrayList(usize).init(allocator); 111 defer nextstack.deinit(); 112 113 stacktrace = std.ArrayList(usize).init(allocator); 114 defer stacktrace.deinit(); 115 116 lineit = std.mem.tokenize(u8, try aoc.unwrap(partit.next()), "\n"); 117 var count: usize = 0; 118 while (lineit.next()) |line| { 119 count += 1; 120 if (try checkRule(&rules, 0, line, &nextstack)) 121 answer += 1; 122 try nextstack.resize(0); 123 } 124 125 return try std.fmt.allocPrint(allocator, "{}", .{answer}); 126} 127 128fn part2(allocator: std.mem.Allocator, input: []u8, args: [][]u8) !?[]u8 { 129 _ = args; 130 131 var rules = std.AutoHashMap(usize, Rule).init(allocator); 132 defer freeRules(allocator, &rules, ([_]usize{ 8, 11 })[0..]); 133 134 var partit = std.mem.split(u8, input, "\n\n"); 135 136 var lineit = std.mem.tokenize(u8, try aoc.unwrap(partit.next()), "\n"); 137 while (lineit.next()) |line| { 138 if (std.mem.eql(u8, line[0..2], "8:")) { 139 const p1: []const usize = ([_]usize{42})[0..]; 140 const p2: []const usize = ([_]usize{ 42, 8 })[0..]; 141 try rules.put(8, Rule{ .combos = ([_][]const usize{ p1, p2 })[0..] }); 142 } else if (std.mem.eql(u8, line[0..3], "11:")) { 143 const p1: []const usize = ([_]usize{ 42, 31 })[0..]; 144 const p2: []const usize = ([_]usize{ 42, 11, 31 })[0..]; 145 try rules.put(11, Rule{ .combos = ([_][]const usize{ p1, p2 })[0..] }); 146 } else { 147 try parseRule(allocator, &rules, line); 148 } 149 } 150 151 var answer: u32 = 0; 152 var nextstack = std.ArrayList(usize).init(allocator); 153 defer nextstack.deinit(); 154 155 stacktrace = std.ArrayList(usize).init(allocator); 156 defer stacktrace.deinit(); 157 158 var count: usize = 0; 159 lineit = std.mem.tokenize(u8, try aoc.unwrap(partit.next()), "\n"); 160 while (lineit.next()) |line| { 161 count += 1; 162 const valid = try checkRule(&rules, 0, line, &nextstack); 163 answer += @boolToInt(valid); 164 if (aoc.debug) { 165 aoc.debugfmt("TRACE: [", .{}); 166 std.mem.reverse(usize, stacktrace.items); 167 printSlice(stacktrace.items); 168 aoc.debugfmt("]\n", .{}); 169 if (valid) { 170 aoc.debugfmt("MATCH {s}\n\n", .{line}); 171 } else { 172 aoc.debugfmt("NO MATCH {s}\n\n", .{line}); 173 } 174 } 175 try nextstack.resize(0); 176 } 177 178 return try std.fmt.allocPrint(allocator, "{}", .{answer}); 179} 180 181pub const main = aoc.main(part1, part2, .{ "134", "377" });