day12 part1
This commit is contained in:
		
							
								
								
									
										119
									
								
								src/day12.zig
									
									
									
									
									
								
							
							
						
						
									
										119
									
								
								src/day12.zig
									
									
									
									
									
								
							| @@ -14,21 +14,117 @@ const Solution = struct { | |||||||
|     b: usize, |     b: usize, | ||||||
| }; | }; | ||||||
|  |  | ||||||
| fn solve(alloc: mem.Allocator, input: []const u8) !Solution { | fn hash(alloc: mem.Allocator, pattern: []const u8, groups: []const u8, curr_group: u8) ![]const u8 { | ||||||
|     _ = alloc; |     var a = try std.ArrayList(u8).initCapacity(alloc, pattern.len + groups.len + curr_group); | ||||||
|  |     try a.appendSlice(pattern); | ||||||
|  |     try a.appendSlice(groups); | ||||||
|  |     try a.append(curr_group); | ||||||
|  |     return try a.toOwnedSlice(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Mystery records to whether they fit. | ||||||
|  | var memo: std.StringHashMap(u32) = undefined; | ||||||
|  |  | ||||||
|  | fn copy(comptime T: type, alloc: mem.Allocator, s: []const T) ![]T { | ||||||
|  |     var a = try std.ArrayList(T).initCapacity(alloc, s.len); | ||||||
|  |     try a.insertSlice(0, s); | ||||||
|  |     return try a.toOwnedSlice(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | fn solvePattern(alloc: mem.Allocator, pattern: []const u8, groups: []const u8, curr_group: u8) !u32 { | ||||||
|  |     std.debug.print("{s}, {any}, {}\n", .{ pattern, groups, curr_group }); | ||||||
|  |  | ||||||
|  |     const h = try hash(alloc, pattern, groups, curr_group); | ||||||
|  |     if (memo.get(h)) |m| { | ||||||
|  |         alloc.free(h); | ||||||
|  |         std.debug.print("==> short-circuit {}\n", .{m}); | ||||||
|  |         return m; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (pattern.len == 0) { | ||||||
|  |         std.debug.print("=> done ok: {}\n", .{groups.len == 0}); | ||||||
|  |         return if (groups.len == 0) 1 else 0; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     const res: u32 = b: { | ||||||
|  |         switch (pattern[0]) { | ||||||
|  |             '#' => { | ||||||
|  |                 // Too many # | ||||||
|  |                 if (groups.len == 0 or curr_group >= groups[0]) { | ||||||
|  |                     std.debug.print("== bad fit\n", .{}); | ||||||
|  |                     break :b 0; | ||||||
|  |                 } | ||||||
|  |                 // Special-case last # | ||||||
|  |                 if (pattern.len == 1 and groups.len == 1 and groups[0] == curr_group + 1) { | ||||||
|  |                     break :b 1; | ||||||
|  |                 } | ||||||
|  |                 break :b try solvePattern(alloc, pattern[1..], groups, curr_group + 1); | ||||||
|  |             }, | ||||||
|  |             '.' => { | ||||||
|  |                 if (curr_group > 0) { | ||||||
|  |                     if (groups.len == 0 or curr_group != groups[0]) { | ||||||
|  |                         // Too many # | ||||||
|  |                         std.debug.print("== bad fit\n", .{}); | ||||||
|  |                         break :b 0; | ||||||
|  |                     } else { | ||||||
|  |                         // Group done | ||||||
|  |                         std.debug.print("=> group {} ok\n", .{groups[0]}); | ||||||
|  |                         break :b try solvePattern(alloc, pattern[1..], groups[1..], 0); | ||||||
|  |                     } | ||||||
|  |                 } else { | ||||||
|  |                     // Not growing a group, skip. | ||||||
|  |                     break :b try solvePattern(alloc, pattern[1..], groups, 0); | ||||||
|  |                 } | ||||||
|  |             }, | ||||||
|  |             '?' => { | ||||||
|  |                 const p1 = try copy(u8, alloc, pattern); | ||||||
|  |                 defer alloc.free(p1); | ||||||
|  |                 const p2 = try copy(u8, alloc, pattern); | ||||||
|  |                 defer alloc.free(p2); | ||||||
|  |  | ||||||
|  |                 p1[0] = '#'; | ||||||
|  |                 p2[0] = '.'; | ||||||
|  |  | ||||||
|  |                 std.debug.print("=> test ?\n", .{}); | ||||||
|  |                 break :b try solvePattern(alloc, p1, groups, curr_group) + | ||||||
|  |                     try solvePattern(alloc, p2, groups, curr_group); | ||||||
|  |             }, | ||||||
|  |             else => unreachable, | ||||||
|  |         } | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     std.debug.print("<= {s}, {any}, {} = {}\n", .{ pattern, groups, curr_group, res }); | ||||||
|  |     try memo.put(h, res); | ||||||
|  |  | ||||||
|  |     return res; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | fn solve(alloc: mem.Allocator, input: []const u8) !Solution { | ||||||
|  |     memo = std.StringHashMap(u32).init(alloc); | ||||||
|  |     defer memo.deinit(); | ||||||
|  |  | ||||||
|  |     var sum: u32 = 0; | ||||||
|     var it = util.splitLines(input); |     var it = util.splitLines(input); | ||||||
|     while (it.next()) |line| { |     while (it.next()) |line| { | ||||||
|         if (line.len == 0) continue; |         if (line.len == 0) continue; | ||||||
|  |  | ||||||
|         var lit = util.splitSpace(line); |         var lit = util.splitSpace(line); | ||||||
|         const record = lit.next().?; |         const pattern = lit.next().?; | ||||||
|         _ = record; |         const raw_groups = lit.next().?; | ||||||
|         const groups = lit.next().?; |         const groups = try util.parseIntsScalar(u8, alloc, raw_groups, .{ .sep = ',' }); | ||||||
|         _ = groups; |         defer alloc.free(groups); | ||||||
|  |  | ||||||
|  |         std.debug.print("-----------------------------------------------\n", .{}); | ||||||
|  |         sum += try solvePattern(alloc, pattern, groups, 0); | ||||||
|  |         std.debug.print("{}\n", .{sum}); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     return .{ .a = 0, .b = 0 }; |     var mkeys = memo.keyIterator(); | ||||||
|  |     while (mkeys.next()) |k| { | ||||||
|  |         alloc.free(k.*); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return .{ .a = sum, .b = 0 }; | ||||||
| } | } | ||||||
|  |  | ||||||
| test "silver" { | test "silver" { | ||||||
| @@ -46,8 +142,13 @@ test "silver" { | |||||||
|  |  | ||||||
| test "gold" { | test "gold" { | ||||||
|     const input = |     const input = | ||||||
|         \\ |         \\???.### 1,1,3 | ||||||
|  |         \\.??..??...?##. 1,1,3 | ||||||
|  |         \\?#?#?#?#?#?#?#? 1,3,1,6 | ||||||
|  |         \\????.#...#... 4,1,1 | ||||||
|  |         \\????.######..#####. 1,6,5 | ||||||
|  |         \\?###???????? 3,2,1 | ||||||
|     ; |     ; | ||||||
|     const sln = try solve(std.testing.allocator, input); |     const sln = try solve(std.testing.allocator, input); | ||||||
|     try std.testing.expectEqual(@as(usize, 0), sln.b); |     try std.testing.expectEqual(@as(usize, 525152), sln.b); | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user