Bläddra i källkod

added filling in small spaces

Aleksei Dorokhov 7 månader sedan
förälder
incheckning
7f7bad41f9
3 ändrade filer med 153 tillägg och 12 borttagningar
  1. 4 0
      day12/coord.zig
  2. 40 12
      day12/day12a.zig
  3. 109 0
      day12/unionfind.zig

+ 4 - 0
day12/coord.zig

@@ -0,0 +1,4 @@
+pub const Coord = struct {
+    row: i32,
+    col: i32,
+};

+ 40 - 12
day12/day12a.zig

@@ -3,20 +3,20 @@ const std = @import("std");
 const shapeModule = @import("shape.zig");
 const shapeModule = @import("shape.zig");
 const inputModule = @import("input.zig");
 const inputModule = @import("input.zig");
 const areaModule = @import("area.zig");
 const areaModule = @import("area.zig");
+const coordModule = @import("coord.zig");
+const unionFindModule = @import("unionfind.zig");
 
 
 const Shape = shapeModule.Shape;
 const Shape = shapeModule.Shape;
 const Area = areaModule.Area;
 const Area = areaModule.Area;
+const Coord = coordModule.Coord;
+const UnionFind = unionFindModule.UnionFind;
+
 const kShapeSize = shapeModule.kShapeSize;
 const kShapeSize = shapeModule.kShapeSize;
 const readInputIntoString = inputModule.readInputIntoString;
 const readInputIntoString = inputModule.readInputIntoString;
 const parseInput = inputModule.parseInput;
 const parseInput = inputModule.parseInput;
 
 
-const Coord = struct {
-    row: i32,
-    col: i32,
-};
-
 pub fn getEligibleCoords(allocator: std.mem.Allocator,
 pub fn getEligibleCoords(allocator: std.mem.Allocator,
-                         area: Area,
+                         area: *const Area,
                          eligibleCoords: *std.ArrayList(Coord)) !void {
                          eligibleCoords: *std.ArrayList(Coord)) !void {
     eligibleCoords.clearRetainingCapacity();
     eligibleCoords.clearRetainingCapacity();
 
 
@@ -73,9 +73,10 @@ pub fn calcShapesTotalSize(shapeCounts: []i32, shapeSizes: []usize) usize {
 }
 }
 
 
 
 
-pub fn canContainShapes(allocator: std.mem.Allocator, area: Area,
+pub fn canContainShapes(allocator: std.mem.Allocator, area: *const Area,
                         shapeCounts: []i32, shapeTransforms: []const []const Shape,
                         shapeCounts: []i32, shapeTransforms: []const []const Shape,
-                        shapeSizes: []usize) !bool {
+                        shapeSizes: []usize,
+                        minShapeSize: usize) !bool {
     // try std.fs.File.stdout().writeAll("canContainShapes: [");
     // try std.fs.File.stdout().writeAll("canContainShapes: [");
     // for (shapeCounts) |shapeCount| {
     // for (shapeCounts) |shapeCount| {
     //     try std.fs.File.stdout().writeAll(
     //     try std.fs.File.stdout().writeAll(
@@ -117,10 +118,29 @@ pub fn canContainShapes(allocator: std.mem.Allocator, area: Area,
                 if (try area.appendShape(
                 if (try area.appendShape(
                       allocator,
                       allocator,
                       &shapeTransforms[shapeIndex][shapeVariant],
                       &shapeTransforms[shapeIndex][shapeVariant],
-                      @intCast(row), @intCast(col), '#')) |newArea| {
+                      @intCast(row), @intCast(col), '#')) |*newArea| {
                     defer newArea.deinit();
                     defer newArea.deinit();
 
 
-                    // try std.fs.File.stdout().writeAll("Step: \n");
+                    // try std.fs.File.stdout().writeAll("Before union find: \n");
+                    // try newArea.print(allocator);
+                    // try std.fs.File.stdout().writeAll("\n");
+
+                    var mutableArea: Area = newArea.*;
+                    var unionFind = try UnionFind.init(allocator, &mutableArea);
+                    for (0 .. @intCast(mutableArea.rows)) |unionRow| {
+                        for (0 .. @intCast(mutableArea.cols)) |unionCol| {
+                            if (mutableArea.getCell(@intCast(unionRow), @intCast(unionCol)) == '.') {
+                                const nodeAIndex:usize = @intCast(unionRow*@abs(mutableArea.cols) + unionCol);
+                                const nodeARootIndex = unionFind.Find(nodeAIndex);
+                                if (unionFind.nodes[nodeARootIndex].size < minShapeSize) {
+                                    mutableArea.setCell(@intCast(unionRow), @intCast(unionCol), '#');
+                                }
+                            }
+                        }
+                    }
+                    unionFind.deinit();
+
+                    // try std.fs.File.stdout().writeAll("After union find: \n");
                     // try newArea.print(allocator);
                     // try newArea.print(allocator);
                     // try std.fs.File.stdout().writeAll("\n");
                     // try std.fs.File.stdout().writeAll("\n");
 
 
@@ -130,7 +150,7 @@ pub fn canContainShapes(allocator: std.mem.Allocator, area: Area,
                     newShapeCounts[shapeIndex] -= 1;
                     newShapeCounts[shapeIndex] -= 1;
 
 
                     if (try canContainShapes(allocator, newArea, newShapeCounts,
                     if (try canContainShapes(allocator, newArea, newShapeCounts,
-                                             shapeTransforms, shapeSizes)) {
+                                             shapeTransforms, shapeSizes, minShapeSize)) {
                         return true;
                         return true;
                     }
                     }
                 }
                 }
@@ -176,12 +196,20 @@ pub fn main() !void {
     const shapeSizes = try calculateShapeSizes(allocator, shapeTransforms);
     const shapeSizes = try calculateShapeSizes(allocator, shapeTransforms);
     defer allocator.free(shapeSizes);
     defer allocator.free(shapeSizes);
 
 
+    var minShapeSize = shapeSizes[0];
+    for (shapeSizes) |shapeSize| {
+        if (shapeSize < minShapeSize) {
+            minShapeSize = shapeSize;
+        }
+    }
+
     var counter: usize = 0;
     var counter: usize = 0;
     for (0..input.areas.len) |i| {
     for (0..input.areas.len) |i| {
         const area = try Area.init(allocator, input.areas[i].rows, input.areas[i].cols);
         const area = try Area.init(allocator, input.areas[i].rows, input.areas[i].cols);
         defer area.deinit();
         defer area.deinit();
         
         
-        if(try canContainShapes(allocator, area, input.areas[i].shapesCount, shapeTransforms, shapeSizes)) {
+        if(try canContainShapes(allocator, &area, input.areas[i].shapesCount,
+                                shapeTransforms, shapeSizes, minShapeSize)) {
             try std.fs.File.stdout().writeAll("Can contain shapes!\n");
             try std.fs.File.stdout().writeAll("Can contain shapes!\n");
             counter += 1;
             counter += 1;
         }
         }

+ 109 - 0
day12/unionfind.zig

@@ -0,0 +1,109 @@
+const std = @import("std");
+
+const coordModule = @import("coord.zig");
+const areaModule = @import("area.zig");
+
+const Coord = coordModule.Coord;
+const Area = areaModule.Area;
+
+pub const UnionFindNode = struct {
+    parent: usize,
+    size: usize,
+};
+
+pub const UnionFind  = struct {
+    nodes: []UnionFindNode,
+    nodesAllocator: std.mem.Allocator,
+
+    pub fn Find(self: *UnionFind, nodeIndex: usize) usize {
+        if (self.nodes[nodeIndex].parent == nodeIndex) {
+            return nodeIndex;
+        }
+
+        self.nodes[nodeIndex].parent = self.Find(self.nodes[nodeIndex].parent);
+        return self.nodes[nodeIndex].parent;
+    }
+
+    fn Union(self: *UnionFind, nodeAIndex: usize, nodeBIndex: usize) bool {
+        var nodeARootIndex = self.Find(nodeAIndex);
+        var nodeBRootIndex = self.Find(nodeBIndex);
+
+        if (nodeARootIndex == nodeBRootIndex) {
+            return false;
+        }
+
+        if (self.nodes[nodeARootIndex].size < self.nodes[nodeBRootIndex].size) {
+            const t = nodeBRootIndex;
+            nodeBRootIndex = nodeARootIndex;
+            nodeARootIndex = t;
+        }
+
+        self.nodes[nodeBRootIndex].parent = nodeARootIndex;
+        self.nodes[nodeARootIndex].size += self.nodes[nodeBRootIndex].size;
+        return true;
+    }
+
+    fn UnionIteration(self: *UnionFind, area: *const Area) bool {
+        var performedUnion = false;
+        for (0 .. @intCast(area.rows)) |row| {
+            for (0 .. @intCast(area.cols)) |col| {
+                const nodeAIndex:usize = @intCast(row*@abs(area.cols) + col);
+                if (area.getCell(@intCast(row), @intCast(col)) == '.') {
+                    if (row > 0 and area.getCell(@intCast(row-1), @intCast(col)) == '.') {
+                        const nodeBIndex: usize = @intCast((row-1)*@abs(area.cols) + col);
+                        if (self.Union(nodeAIndex, nodeBIndex)) {
+                            performedUnion = true;
+                        }
+                    }
+
+                    if (col > 0 and area.getCell(@intCast(row), @intCast(col-1)) == '.') {
+                        const nodeBIndex: usize = @intCast(row*@abs(area.cols) + col - 1);
+                        if (self.Union(nodeAIndex, nodeBIndex)) {
+                            performedUnion = true;
+                        }
+                    }
+
+                    if (row < area.rows - 1 and area.getCell(@intCast(row+1), @intCast(col)) == '.') {
+                        const nodeBIndex: usize = @intCast((row+1)*@abs(area.cols) + col);
+                        if (self.Union(nodeAIndex, nodeBIndex)) {
+                            performedUnion = true;
+                        }
+                    }
+
+                    if (col < area.cols - 1 and area.getCell(@intCast(row), @intCast(col+1)) == '.') {
+                        const nodeBIndex: usize = @intCast(row*@abs(area.cols) + col + 1);
+                        if (self.Union(nodeAIndex, nodeBIndex)) {
+                            performedUnion = true;
+                        }
+                    }
+                }
+            }
+        }
+
+        return performedUnion;
+    }
+
+    pub fn init(allocator: std.mem.Allocator, area: *const Area) !UnionFind {
+        var unionFind: UnionFind  = .{
+            .nodes = try allocator.alloc(UnionFindNode, @intCast(area.rows*area.cols)),
+            .nodesAllocator = allocator,
+        };
+
+        for (0..unionFind.nodes.len) |i| {
+            unionFind.nodes[i].parent = i;
+            unionFind.nodes[i].size = 1;
+        }
+
+        while (true) {
+          if (!unionFind.UnionIteration(area)) {
+            break;
+          }
+        }
+
+        return unionFind;
+    }
+
+    pub fn deinit(self: *const UnionFind) void {
+        self.nodesAllocator.free(self.nodes);
+    }
+};