1
0

Compare commits

..

No commits in common. "fa7a9aab14320494b0c4f577e3c007b3be9b770c" and "30d638ca513888fd7d585130d8f3ee53b65cf065" have entirely different histories.

View File

@ -14,126 +14,21 @@ const Solution = struct {
b: usize, b: usize,
}; };
fn hash(alloc: mem.Allocator, pattern: []const u8, groups: []const u8, curr_group: u8) ![]u8 {
var a = try std.ArrayList(u8).initCapacity(alloc, pattern.len + groups.len + 1);
try a.appendSlice(pattern);
try a.appendSlice(groups);
try a.append(curr_group);
return try a.toOwnedSlice();
}
var memo: std.StringHashMap(usize) = undefined;
fn clone(comptime T: type, alloc: mem.Allocator, s: []const T) ![]T {
var a = try alloc.alloc(T, s.len);
@memcpy(a, s);
return a;
}
fn solvePattern(alloc: mem.Allocator, pattern: []const u8, groups: []const u8, curr_group: u8) !usize {
const h = try hash(alloc, pattern, groups, curr_group);
if (memo.get(h)) |m| {
alloc.free(h);
return m;
}
if (pattern.len == 0) {
return if (groups.len == 0) 1 else 0;
}
const res: usize = b: {
switch (pattern[0]) {
'#' => {
// Too many #
if (groups.len == 0 or curr_group >= groups[0]) {
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 #
break :b 0;
} else {
// Group done
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 clone(u8, alloc, pattern);
defer alloc.free(p1);
const p2 = try clone(u8, alloc, pattern);
defer alloc.free(p2);
p1[0] = '#';
p2[0] = '.';
break :b try solvePattern(alloc, p1, groups, curr_group) +
try solvePattern(alloc, p2, groups, curr_group);
},
else => unreachable,
}
};
try memo.put(h, res);
return res;
}
fn unfold(alloc: mem.Allocator, input: []const u8, sep: u8) ![]const u8 {
var buf = try std.ArrayList(u8).initCapacity(alloc, input.len * 5 + 5);
for (0..5) |i| {
if (i > 0 and sep > 0) try buf.append(sep);
try buf.appendSlice(input);
}
return try buf.toOwnedSlice();
}
fn solve(alloc: mem.Allocator, input: []const u8) !Solution { fn solve(alloc: mem.Allocator, input: []const u8) !Solution {
memo = std.StringHashMap(usize).init(alloc); _ = alloc;
defer memo.deinit();
var sum1: usize = 0;
var sum2: usize = 0;
var it = util.splitLines(input); var it = util.splitLines(input);
var i: usize = 1;
while (it.next()) |line| { while (it.next()) |line| {
if (line.len == 0) continue; if (line.len == 0) continue;
std.debug.print("line {} ", .{i});
var lit = util.splitSpace(line); var lit = util.splitSpace(line);
const pattern = lit.next().?; const record = lit.next().?;
const raw_groups = lit.next().?; _ = record;
const groups = try util.parseIntsScalar(u8, alloc, raw_groups, .{ .sep = ',' }); const groups = lit.next().?;
defer alloc.free(groups); _ = groups;
const unfolded_pattern = try unfold(alloc, pattern, '?');
const unfolded_groups = try unfold(alloc, groups, 0);
defer alloc.free(unfolded_pattern);
defer alloc.free(unfolded_groups);
sum1 += try solvePattern(alloc, pattern, groups, 0);
sum2 += try solvePattern(alloc, unfolded_pattern, unfolded_groups, 0);
std.debug.print("{} {}\n", .{ sum1, sum2 });
i += 1;
} }
var mkeys = memo.keyIterator(); return .{ .a = 0, .b = 0 };
while (mkeys.next()) |k| {
alloc.free(k.*);
}
return .{ .a = sum1, .b = sum2 };
} }
test "silver" { test "silver" {
@ -151,13 +46,8 @@ 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, 525152), sln.b); try std.testing.expectEqual(@as(usize, 0), sln.b);
} }