2024 Day 12 Part 2
This commit is contained in:
parent
18555d687d
commit
bb360807ba
1 changed files with 88 additions and 8 deletions
|
|
@ -20,11 +20,32 @@ pub fn main() !void {
|
||||||
var bw = std.io.bufferedWriter(std.io.getStdOut().writer());
|
var bw = std.io.bufferedWriter(std.io.getStdOut().writer());
|
||||||
const stdout = bw.writer();
|
const stdout = bw.writer();
|
||||||
|
|
||||||
try stdout.print("{d}\n", .{try part1(allocator, grid)});
|
const regions = try garden(allocator, grid);
|
||||||
|
defer regions.deinit();
|
||||||
|
defer for (regions.items) |*region| region.deinit();
|
||||||
|
|
||||||
|
try stdout.print("{d}\n", .{part1(regions.items)});
|
||||||
|
try stdout.print("{d}\n", .{part2(regions.items)});
|
||||||
try bw.flush();
|
try bw.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn part1(allocator: Allocator, grid: Grid) !u64 {
|
fn part1(regions: []Region) u64 {
|
||||||
|
var cost: u64 = 0;
|
||||||
|
for (regions) |region| {
|
||||||
|
cost += region.fencingCost1();
|
||||||
|
}
|
||||||
|
return cost;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part2(regions: []Region) u64 {
|
||||||
|
var cost: u64 = 0;
|
||||||
|
for (regions) |region| {
|
||||||
|
cost += region.fencingCost2();
|
||||||
|
}
|
||||||
|
return cost;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn garden(allocator: Allocator, grid: Grid) !List(Region) {
|
||||||
var unused = Set(Pos).init(allocator);
|
var unused = Set(Pos).init(allocator);
|
||||||
defer unused.deinit();
|
defer unused.deinit();
|
||||||
{
|
{
|
||||||
|
|
@ -38,12 +59,11 @@ fn part1(allocator: Allocator, grid: Grid) !u64 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var cost: u64 = 0;
|
var regions = List(Region).init(allocator);
|
||||||
while (unused.pop()) |root| {
|
while (unused.pop()) |root| {
|
||||||
const label = grid.get(root).?;
|
const label = grid.get(root).?;
|
||||||
|
|
||||||
var region = Region.init(allocator, label);
|
var region = Region.init(allocator, label);
|
||||||
defer region.deinit();
|
|
||||||
|
|
||||||
var queue = List(Pos).init(allocator);
|
var queue = List(Pos).init(allocator);
|
||||||
defer queue.deinit();
|
defer queue.deinit();
|
||||||
|
|
@ -61,10 +81,9 @@ fn part1(allocator: Allocator, grid: Grid) !u64 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cost += region.fencingCost();
|
try regions.append(region);
|
||||||
}
|
}
|
||||||
|
return regions;
|
||||||
return cost;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const Region = struct {
|
const Region = struct {
|
||||||
|
|
@ -111,9 +130,70 @@ const Region = struct {
|
||||||
try self.cells.put(pos);
|
try self.cells.put(pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fencingCost(self: Self) u64 {
|
fn fencingCost1(self: Self) u64 {
|
||||||
return self.area() * self.perimeter;
|
return self.area() * self.perimeter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn boundingBox(self: Self) ?struct { Pos, Pos } {
|
||||||
|
var it = self.cells.iterator();
|
||||||
|
const first = it.next() orelse return null;
|
||||||
|
|
||||||
|
var lo = first.*;
|
||||||
|
var hi = lo;
|
||||||
|
|
||||||
|
while (it.next()) |pos| {
|
||||||
|
lo = Pos.new(@min(lo.r, pos.r), @min(lo.c, pos.c));
|
||||||
|
hi = Pos.new(@max(hi.r, pos.r), @max(hi.c, pos.c));
|
||||||
|
}
|
||||||
|
|
||||||
|
return .{ lo, hi };
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fencingCost2(self: Self) usize {
|
||||||
|
var sides: usize = 0;
|
||||||
|
|
||||||
|
const lo, const hi = self.boundingBox().?;
|
||||||
|
|
||||||
|
// Walk the grid lines from all four directions, counting the number of
|
||||||
|
// line segments that lie on the edge of the shape (i.e., don't have a
|
||||||
|
// neighbor in the direction we're looking from).
|
||||||
|
|
||||||
|
inline for ([_]Direction{ .n, .s }) |dir| {
|
||||||
|
var r: i32 = lo.r;
|
||||||
|
while (r <= hi.r) : (r += 1) {
|
||||||
|
var c: i32 = lo.c;
|
||||||
|
var wasEdge = false;
|
||||||
|
while (c <= hi.c) : (c += 1) {
|
||||||
|
const pos = Pos.new(r, c);
|
||||||
|
const neighbor = pos.add(dir.delta());
|
||||||
|
const isEdge = self.cells.contains(pos) and !self.cells.contains(neighbor);
|
||||||
|
if (!wasEdge and isEdge) {
|
||||||
|
sides += 1;
|
||||||
|
}
|
||||||
|
wasEdge = isEdge;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline for ([_]Direction{ .w, .e }) |dir| {
|
||||||
|
var c: i32 = lo.c;
|
||||||
|
while (c <= hi.c) : (c += 1) {
|
||||||
|
var r: i32 = lo.r;
|
||||||
|
var wasEdge = false;
|
||||||
|
while (r <= hi.r) : (r += 1) {
|
||||||
|
const pos = Pos.new(r, c);
|
||||||
|
const neighbor = pos.add(dir.delta());
|
||||||
|
const isEdge = self.cells.contains(pos) and !self.cells.contains(neighbor);
|
||||||
|
if (!wasEdge and isEdge) {
|
||||||
|
sides += 1;
|
||||||
|
}
|
||||||
|
wasEdge = isEdge;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return self.area() * sides;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const Pos = struct {
|
const Pos = struct {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue