solve day 19 part 2
This commit is contained in:
parent
722811225c
commit
ff8924991c
153
src/day19.zig
153
src/day19.zig
@ -45,7 +45,7 @@ const Rule = struct {
|
||||
condition: RuleCondition,
|
||||
property: PartProperty = .X,
|
||||
next: NameString,
|
||||
value: u32 = 0,
|
||||
value: u16 = 0,
|
||||
};
|
||||
|
||||
const Workflow = std.ArrayList(Rule);
|
||||
@ -57,6 +57,43 @@ const MachinePart = struct {
|
||||
s: u32 = 0
|
||||
};
|
||||
|
||||
const PropertyRange = struct {
|
||||
min: u16,
|
||||
max: u16,
|
||||
|
||||
fn is_empty(self: @This()) bool {
|
||||
return self.min > self.max;
|
||||
}
|
||||
|
||||
fn size(self: @This()) u64 {
|
||||
return (self.max - self.min) + 1;
|
||||
}
|
||||
};
|
||||
|
||||
const MachinePartRange = struct {
|
||||
x: PropertyRange,
|
||||
m: PropertyRange,
|
||||
a: PropertyRange,
|
||||
s: PropertyRange,
|
||||
|
||||
fn get(self: *MachinePartRange, prop: PartProperty) *PropertyRange {
|
||||
return switch (prop) {
|
||||
.X => &self.x,
|
||||
.M => &self.m,
|
||||
.A => &self.a,
|
||||
.S => &self.s,
|
||||
};
|
||||
}
|
||||
|
||||
fn is_empty(self: MachinePartRange) bool {
|
||||
return self.x.is_empty() or self.m.is_empty() or self.a.is_empty() or self.s.is_empty();
|
||||
}
|
||||
|
||||
fn size(self: MachinePartRange) u64 {
|
||||
return self.x.size() * self.m.size() * self.a.size() * self.s.size();
|
||||
}
|
||||
};
|
||||
|
||||
const Input = struct {
|
||||
workflows: std.AutoHashMap(NameString, Workflow),
|
||||
machine_parts: std.ArrayList(MachinePart),
|
||||
@ -78,17 +115,21 @@ const Input = struct {
|
||||
}
|
||||
};
|
||||
|
||||
fn print_rule(rule: Rule) void {
|
||||
switch (rule.condition) {
|
||||
.Always => std.debug.print("{s}", .{rule.next.slice()}),
|
||||
.Less => std.debug.print("{s}<{}:{s}", .{rule.property.to_str(), rule.value, rule.next.slice()}),
|
||||
.More => std.debug.print("{s}>{}:{s}", .{rule.property.to_str(), rule.value, rule.next.slice()})
|
||||
}
|
||||
}
|
||||
|
||||
fn print_workflow(workflow: Workflow) void {
|
||||
std.debug.print("{{", .{});
|
||||
for (0.., workflow.items) |i, rule| {
|
||||
if (i > 0) {
|
||||
std.debug.print(",", .{});
|
||||
}
|
||||
switch (rule.condition) {
|
||||
.Always => std.debug.print("{s}", .{rule.next.slice()}),
|
||||
.Less => std.debug.print("{s}<{}:{s}", .{rule.property.to_str(), rule.value, rule.next.slice()}),
|
||||
.More => std.debug.print("{s}>{}:{s}", .{rule.property.to_str(), rule.value, rule.next.slice()})
|
||||
}
|
||||
print_rule(rule);
|
||||
}
|
||||
std.debug.print("}}\n", .{});
|
||||
}
|
||||
@ -119,7 +160,7 @@ fn parse_workflow(allocator: Allocator, line: []const u8) !std.meta.Tuple(&.{ Na
|
||||
try parsed.append(Rule{
|
||||
.condition = condition,
|
||||
.property = PartProperty.from_str(rule_str[0..cmp_idx]) orelse return error.Invalid,
|
||||
.value = try std.fmt.parseUnsigned(u32, rule_str[(cmp_idx+1)..colon], 10),
|
||||
.value = try std.fmt.parseUnsigned(u16, rule_str[(cmp_idx+1)..colon], 10),
|
||||
.next = try NameString.fromSlice(rule_str[(colon+1)..])
|
||||
});
|
||||
} else {
|
||||
@ -264,7 +305,101 @@ pub fn part2(input: *aoc.Input) !aoc.Result {
|
||||
var parsed = try parse_input(allocator, input.lines);
|
||||
defer parsed.deinit();
|
||||
|
||||
return .{ .uint = 0 };
|
||||
const State = struct {
|
||||
name: NameString,
|
||||
machine_part: MachinePartRange,
|
||||
};
|
||||
|
||||
var stack = std.ArrayList(State).init(allocator);
|
||||
defer stack.deinit();
|
||||
|
||||
try stack.append(State{
|
||||
.name = try NameString.fromSlice("in"),
|
||||
.machine_part = MachinePartRange{
|
||||
.x = PropertyRange{ .min = 1, .max = 4000 },
|
||||
.m = PropertyRange{ .min = 1, .max = 4000 },
|
||||
.a = PropertyRange{ .min = 1, .max = 4000 },
|
||||
.s = PropertyRange{ .min = 1, .max = 4000 },
|
||||
}
|
||||
});
|
||||
|
||||
var accepted_count: u64 = 0;
|
||||
|
||||
while (stack.popOrNull()) |state| {
|
||||
var current: MachinePartRange = state.machine_part;
|
||||
|
||||
const name_str = state.name.slice();
|
||||
if (std.mem.eql(u8, name_str, "A")) {
|
||||
accepted_count += current.size();
|
||||
continue;
|
||||
} else if (std.mem.eql(u8, name_str, "R")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const workflow: Workflow = parsed.workflows.get(state.name).?;
|
||||
for (workflow.items) |rule| {
|
||||
if (current.is_empty()) break;
|
||||
|
||||
if (rule.condition == .Always) {
|
||||
try stack.append(State{
|
||||
.name = rule.next,
|
||||
.machine_part = current,
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
var current_property_range = current.get(rule.property);
|
||||
|
||||
var is_min_captured = false;
|
||||
var is_max_captured = false;
|
||||
if (rule.condition == .Less) {
|
||||
is_min_captured = current_property_range.min < rule.value;
|
||||
is_max_captured = current_property_range.max < rule.value;
|
||||
} else if (rule.condition == .More) {
|
||||
is_min_captured = current_property_range.min > rule.value;
|
||||
is_max_captured = current_property_range.max > rule.value;
|
||||
} else {
|
||||
unreachable;
|
||||
}
|
||||
|
||||
if (!is_min_captured and !is_max_captured) {
|
||||
// Nothing gets captured by this rule, go to the next rule
|
||||
} else if (is_min_captured and is_max_captured) {
|
||||
// Everything gets captured by this rule, can skip checking other rules
|
||||
try stack.append(State{
|
||||
.name = rule.next,
|
||||
.machine_part = current
|
||||
});
|
||||
break;
|
||||
} else if (!is_min_captured and is_max_captured) {
|
||||
// Only the upper part is captured
|
||||
var upper_machine_parts = current;
|
||||
var upper_property_range = upper_machine_parts.get(rule.property);
|
||||
upper_property_range.min = rule.value + 1;
|
||||
current_property_range.max = rule.value;
|
||||
|
||||
try stack.append(State{
|
||||
.name = rule.next,
|
||||
.machine_part = upper_machine_parts
|
||||
});
|
||||
} else if (is_min_captured and !is_max_captured) {
|
||||
// Only the lower part is captured
|
||||
var lower_machine_parts = current;
|
||||
var lower_property_range = lower_machine_parts.get(rule.property);
|
||||
lower_property_range.max = rule.value - 1;
|
||||
current_property_range.min = rule.value;
|
||||
|
||||
try stack.append(State{
|
||||
.name = rule.next,
|
||||
.machine_part = lower_machine_parts
|
||||
});
|
||||
} else {
|
||||
unreachable;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return .{ .uint = accepted_count };
|
||||
}
|
||||
|
||||
const example_input = [_][]const u8{
|
||||
@ -292,5 +427,5 @@ test "part 1 example" {
|
||||
}
|
||||
|
||||
test "part 2 example" {
|
||||
try aoc.expectAnswerUInt(part1, 167409079868000, &example_input);
|
||||
try aoc.expectAnswerUInt(part2, 167409079868000, &example_input);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user