| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109 |
- 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);
- }
- };
|