solve day 18 part 2
This commit is contained in:
parent
692b178154
commit
14c4b266c1
166
src/day18.zig
166
src/day18.zig
@ -6,6 +6,11 @@ const PointLib = @import("./point.zig");
|
|||||||
const PointI32 = PointLib.PointI32;
|
const PointI32 = PointLib.PointI32;
|
||||||
const PointU32 = PointLib.PointU32;
|
const PointU32 = PointLib.PointU32;
|
||||||
|
|
||||||
|
const Segment = struct {
|
||||||
|
start: PointI32,
|
||||||
|
stop: PointI32,
|
||||||
|
};
|
||||||
|
|
||||||
const Direction = enum {
|
const Direction = enum {
|
||||||
Up,
|
Up,
|
||||||
Down,
|
Down,
|
||||||
@ -66,126 +71,75 @@ fn parse_input1(allocator: Allocator, lines: []const []const u8) !Instructions {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_bounds(insts: Instructions) std.meta.Tuple(&.{ PointI32, PointI32 }) {
|
fn get_bounds(segments: []const Segment) std.meta.Tuple(&.{ PointI32, PointI32 }) {
|
||||||
var upper_left = PointI32.zero();
|
var upper_left = PointI32.zero();
|
||||||
var lower_right = PointI32.zero();
|
var lower_right = PointI32.zero();
|
||||||
|
|
||||||
var current = PointI32.zero();
|
for (segments) |segment| {
|
||||||
for (insts.items) |inst| {
|
inline for (&.{ segment.start, segment.stop }) |p| {
|
||||||
const step = inst.dir.to_offset().mul(@intCast(inst.steps));
|
upper_left.x = @min(upper_left.x, p.x);
|
||||||
current = current.add(step);
|
upper_left.y = @min(upper_left.y, p.y);
|
||||||
|
lower_right.x = @max(lower_right.x, p.x);
|
||||||
upper_left.x = @min(upper_left.x, current.x);
|
lower_right.y = @max(lower_right.y, p.y);
|
||||||
upper_left.y = @min(upper_left.y, current.y);
|
}
|
||||||
lower_right.x = @max(lower_right.x, current.x);
|
|
||||||
lower_right.y = @max(lower_right.y, current.y);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return .{ upper_left, lower_right };
|
return .{ upper_left, lower_right };
|
||||||
}
|
}
|
||||||
|
|
||||||
fn flood_fill(allocator: Allocator, map: []bool, map_size: PointU32, from: PointU32) !void {
|
fn get_segments(allocator: Allocator, insts: Instructions) !std.ArrayList(Segment) {
|
||||||
var stack = std.ArrayList(PointU32).init(allocator);
|
var segments = std.ArrayList(Segment).init(allocator);
|
||||||
defer stack.deinit();
|
errdefer segments.deinit();
|
||||||
|
|
||||||
try stack.append(from);
|
|
||||||
map[from.y * map_size.x + from.x] = true;
|
|
||||||
|
|
||||||
while (stack.popOrNull()) |point| {
|
|
||||||
const directions = [_]Direction{
|
|
||||||
.Up,
|
|
||||||
.Right,
|
|
||||||
.Down,
|
|
||||||
.Left
|
|
||||||
};
|
|
||||||
for (directions) |dir| {
|
|
||||||
const offset = dir.to_offset();
|
|
||||||
const neighbour_x = @as(i32, @intCast(point.x)) + offset.x;
|
|
||||||
const neighbour_y = @as(i32, @intCast(point.y)) + offset.y;
|
|
||||||
|
|
||||||
if (!(0 <= neighbour_x and neighbour_x < map_size.x)) continue;
|
|
||||||
if (!(0 <= neighbour_y and neighbour_y < map_size.y)) continue;
|
|
||||||
|
|
||||||
const neighbour = PointU32{
|
|
||||||
.x = @intCast(neighbour_x),
|
|
||||||
.y = @intCast(neighbour_y)
|
|
||||||
};
|
|
||||||
const neighbour_idx = neighbour.y * map_size.x + neighbour.x;
|
|
||||||
if (!map[neighbour_idx]) {
|
|
||||||
map[neighbour_idx] = true;
|
|
||||||
try stack.append(neighbour);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn find_flood_fill_start(map: []bool, width: u32, height: u32) ?PointU32 {
|
|
||||||
assert(height >= 2);
|
|
||||||
|
|
||||||
var found_wall = false;
|
|
||||||
for (1..height) |y| {
|
|
||||||
for (0..width) |x| {
|
|
||||||
const idx = y * width + x;
|
|
||||||
if (!found_wall) {
|
|
||||||
if (map[idx]) {
|
|
||||||
found_wall = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (!map[idx]) {
|
|
||||||
return PointU32{ .x = @intCast(x), .y = @intCast(y) };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_lagoon_size(allocator: Allocator, instructions: Instructions) !usize {
|
|
||||||
const bounds = get_bounds(instructions);
|
|
||||||
const upper_left: PointI32 = bounds[0];
|
|
||||||
const lower_right: PointI32 = bounds[1];
|
|
||||||
const size = PointU32{
|
|
||||||
.x = @abs(lower_right.x - upper_left.x) + 1,
|
|
||||||
.y = @abs(lower_right.y - upper_left.y) + 1
|
|
||||||
};
|
|
||||||
|
|
||||||
std.debug.print("size: {any}\n", .{size});
|
|
||||||
|
|
||||||
const map = try allocator.alloc(bool, size.x * size.y);
|
|
||||||
defer allocator.free(map);
|
|
||||||
@memset(map, false);
|
|
||||||
|
|
||||||
var current = PointI32.zero();
|
var current = PointI32.zero();
|
||||||
for (instructions.items) |inst| {
|
for (insts.items) |inst| {
|
||||||
const dir_offset = inst.dir.to_offset();
|
const step = inst.dir.to_offset().mul(@intCast(inst.steps));
|
||||||
|
const next = current.add(step);
|
||||||
|
|
||||||
for (0..inst.steps) |i| {
|
try segments.append(Segment{ .start = current, .stop = next });
|
||||||
const pos = current.add(dir_offset.mul(@intCast(i)));
|
|
||||||
const idx = (pos.y - upper_left.y) * @as(i32, @intCast(size.x)) + (pos.x - upper_left.x);
|
|
||||||
map[@intCast(idx)] = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const step = dir_offset.mul(@intCast(inst.steps));
|
current = next;
|
||||||
current = current.add(step);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const flood_fill_start = find_flood_fill_start(map, size.x, size.y) orelse return error.NoFloodFillStart;
|
return segments;
|
||||||
try flood_fill(allocator, map, size, flood_fill_start);
|
}
|
||||||
|
|
||||||
// for (0..size.y) |y| {
|
// GOD DAMN IT, AGAIN WITH THIS THEOROM! I THOUGH IT WAS SCANLINES!
|
||||||
// for (0..size.x) |x| {
|
// Shoelace theorum + Pick's theorum
|
||||||
// const idx = size.x * y + x;
|
// Day 10 all over again :/
|
||||||
// if (map[idx]) {
|
fn get_lagoon_size(allocator: Allocator, instructions: Instructions) !usize {
|
||||||
// std.debug.print("#", .{});
|
var boundry_points: u32 = 0;
|
||||||
// } else {
|
|
||||||
// std.debug.print(".", .{});
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// std.debug.print("\n", .{});
|
|
||||||
// }
|
|
||||||
|
|
||||||
return std.mem.count(bool, map, &.{ true });
|
var loop_path = std.ArrayList(PointI32).init(allocator);
|
||||||
|
defer loop_path.deinit();
|
||||||
|
|
||||||
|
var current = PointI32.zero();
|
||||||
|
try loop_path.append(current);
|
||||||
|
for (instructions.items) |inst| {
|
||||||
|
const step = inst.dir.to_offset().mul(@intCast(inst.steps));
|
||||||
|
current = current.add(step);
|
||||||
|
boundry_points += inst.steps;
|
||||||
|
|
||||||
|
try loop_path.append(current);
|
||||||
|
}
|
||||||
|
|
||||||
|
var twice_area: i64 = 0;
|
||||||
|
for (0..(loop_path.items.len-1)) |i| {
|
||||||
|
const cur = loop_path.items[i];
|
||||||
|
const next = loop_path.items[i+1];
|
||||||
|
|
||||||
|
const y_0: i64 = @intCast(cur.y);
|
||||||
|
const x_0: i64 = @intCast(cur.x);
|
||||||
|
const y_1: i64 = @intCast(next.y);
|
||||||
|
const x_1: i64 = @intCast(next.x);
|
||||||
|
|
||||||
|
twice_area += (x_0 * y_1) - (y_0 * x_1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const iterior_points = @abs(twice_area) / 2 - boundry_points / 2 + 1;
|
||||||
|
const result = iterior_points + boundry_points;
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn part1(input: *aoc.Input) !aoc.Result {
|
pub fn part1(input: *aoc.Input) !aoc.Result {
|
||||||
@ -211,7 +165,7 @@ fn parse_dig_instruction2(line: []const u8) !DigInstruction {
|
|||||||
if (color_trimmed.len != 6) return error.ColorTooShort;
|
if (color_trimmed.len != 6) return error.ColorTooShort;
|
||||||
|
|
||||||
const dir: Direction = switch (color_trimmed[5]) {
|
const dir: Direction = switch (color_trimmed[5]) {
|
||||||
'0' => .Up,
|
'0' => .Right,
|
||||||
'1' => .Down,
|
'1' => .Down,
|
||||||
'2' => .Left,
|
'2' => .Left,
|
||||||
'3' => .Up,
|
'3' => .Up,
|
||||||
@ -220,7 +174,7 @@ fn parse_dig_instruction2(line: []const u8) !DigInstruction {
|
|||||||
|
|
||||||
return DigInstruction{
|
return DigInstruction{
|
||||||
.dir = dir,
|
.dir = dir,
|
||||||
.steps = try std.fmt.parseUnsigned(u32, color_trimmed[1..5], 16)
|
.steps = try std.fmt.parseUnsigned(u32, color_trimmed[0..5], 16)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user