diff --git a/src/day11.zig b/src/day11.zig new file mode 100644 index 0000000..3e062cd --- /dev/null +++ b/src/day11.zig @@ -0,0 +1,144 @@ +const std = @import("std"); +const util = @import("util.zig"); +const mem = std.mem; + +pub fn main() !void { + const input = @embedFile("data/day11.txt"); + const sln = try solve(util.gpa, input); + std.debug.print("{d}\n", .{sln.a}); + std.debug.print("{d}\n", .{sln.b}); +} + +const Solution = struct { + a: usize, + b: usize, +}; + +fn Point(comptime T: type) type { + return struct { x: T, y: T }; +} + +fn findGaps(comptime T: type, alloc: mem.Allocator, occupied: std.AutoHashMap(T, void)) ![]T { + var it = occupied.keyIterator(); + var sorted_occupied = try std.ArrayList(T).initCapacity(alloc, occupied.count()); + defer sorted_occupied.deinit(); + while (it.next()) |item| { + try sorted_occupied.append(item.*); + } + mem.sort(T, sorted_occupied.items, {}, std.sort.asc(T)); + + var gaps = std.ArrayList(T).init(alloc); + errdefer gaps.deinit(); + + var gap: T = 0; + var i: usize = 0; + const max_occ = if (sorted_occupied.items.len != 0) std.mem.max(T, sorted_occupied.items) else 0; + while (gap < max_occ and i < sorted_occupied.items.len) : (gap += 1) { + if (sorted_occupied.items[i] != gap) { + try gaps.append(gap); + } else { + i += 1; + } + } + + return gaps.toOwnedSlice(); +} + +fn expand(comptime T: type, alloc: mem.Allocator, galaxies: []Point(T)) !void { + var seen_cols = std.AutoHashMap(T, void).init(alloc); + defer seen_cols.deinit(); + var seen_rows = std.AutoHashMap(T, void).init(alloc); + defer seen_rows.deinit(); + + for (galaxies) |galaxy| { + try seen_cols.put(galaxy.x, {}); + try seen_rows.put(galaxy.y, {}); + } + + var gap_cols = try findGaps(T, alloc, seen_cols); + defer alloc.free(gap_cols); + var gap_rows = try findGaps(T, alloc, seen_rows); + defer alloc.free(gap_rows); + + std.debug.print("expand x∋{any}, y∋{any}\n", .{ gap_cols, gap_rows }); + + for (0..galaxies.len) |i| { + const galaxy = galaxies[i]; + + var col_offset: T = 0; + for (gap_cols) |gap| { + if (gap > galaxy.x) break; + col_offset += 1; + } + + var row_offset: T = 0; + for (gap_rows) |gap| { + if (gap > galaxy.y) break; + row_offset += 1; + } + + galaxies[i] = Point(T){ .x = galaxy.x + col_offset, .y = galaxy.y + row_offset }; + } +} + +fn absDiff(comptime T: type, a: T, b: T) T { + return @max(a, b) - @min(a, b); +} + +fn solve(alloc: mem.Allocator, input: []const u8) !Solution { + var galaxies = std.ArrayList(Point(usize)).init(alloc); + defer galaxies.deinit(); + + var it = util.splitLines(input); + var y: usize = 0; + while (it.next()) |line| { + if (line.len == 0) continue; + var x: usize = 0; + for (line) |char| { + switch (char) { + '.' => {}, + '#' => try galaxies.append(Point(usize){ .x = x, .y = y }), + else => unreachable, + } + x += 1; + } + y += 1; + } + + try expand(usize, alloc, galaxies.items); + + var distance: usize = 0; + for (galaxies.items, 0..) |a, i| { + for (galaxies.items[i + 1 .. galaxies.items.len]) |b| { + const d = absDiff(usize, a.x, b.x) + absDiff(usize, a.y, b.y); + distance += d; + } + } + + return .{ .a = distance, .b = 0 }; +} + +test "silver" { + const input = + \\...#...... + \\.......#.. + \\#......... + \\.......... + \\......#... + \\.#........ + \\.........# + \\.......... + \\.......#.. + \\#...#..... + ; + const sln = try solve(std.testing.allocator, input); + try std.testing.expectEqual(@as(usize, 374), sln.a); +} + +test "gold" { + const input = + \\ + ; + const sln = try solve(std.testing.allocator, input); + try std.testing.expectEqual(@as(usize, 0), sln.b); +}