From 88505114b052c220454cb6211abd8dcff2ce5323 Mon Sep 17 00:00:00 2001 From: Orfeas <38209077+0xfea5@users.noreply.github.com> Date: Fri, 15 Dec 2023 02:13:13 +0200 Subject: day14 --- day14/solution.zig | 181 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 181 insertions(+) create mode 100644 day14/solution.zig (limited to 'day14/solution.zig') diff --git a/day14/solution.zig b/day14/solution.zig new file mode 100644 index 0000000..5509bdc --- /dev/null +++ b/day14/solution.zig @@ -0,0 +1,181 @@ +const std = @import("std"); +const print = std.debug.print; +const assert = std.debug.assert; +const ArrayList = std.ArrayList; +const HashMap = std.HashMap; +const mem = std.mem; + +const fin = mem.trim(u8, @embedFile("./input.txt"), &std.ascii.whitespace); +var gpa = std.heap.GeneralPurposeAllocator(.{}){}; +const allocator = gpa.allocator(); + +const Map = []const []u8; + +fn column_wise(map: Map, begin: isize, end: isize, step: isize) u64 { + const h = map.len; + const w = map[0].len; + var ans: u64 = 0; + + for (0..w) |j| { + var next_free = begin; + var i = begin; + while (i != end) : (i += step) { + switch (map[@bitCast(i)][j]) { + '.' => {}, + 'O' => { + ans += h - @as(u64, @bitCast(next_free)); + map[@bitCast(i)][j] = '.'; + map[@bitCast(next_free)][j] = 'O'; + next_free += step; + }, + '#' => { + next_free = i + step; + }, + else => unreachable, + } + } + } + + return ans; +} + +fn row_wise(map: Map, begin: isize, end: isize, step: isize) u64 { + const h = map.len; + var ans: u64 = 0; + + for (0..h) |i| { + var next_free = begin; + var j = begin; + while (j != end) : (j += step) { + switch (map[i][@bitCast(j)]) { + '.' => {}, + 'O' => { + ans += h - i; + map[i][@bitCast(j)] = '.'; + map[i][@bitCast(next_free)] = 'O'; + next_free += step; + }, + '#' => { + next_free = j + step; + }, + else => unreachable, + } + } + } + + return ans; +} + +fn north(map: Map) u64 { + const h = map.len; + return column_wise(map, 0, @bitCast(h), 1); +} + +fn west(map: Map) u64 { + const w = map[0].len; + return row_wise(map, 0, @bitCast(w), 1); +} + +fn south(map: Map) u64 { + const h = map.len; + return column_wise(map, @bitCast(h - 1), -1, -1); +} + +fn east(map: Map) u64 { + const w = map[0].len; + return row_wise(map, @bitCast(w - 1), -1, -1); +} + +fn round(map: Map) u64 { + _ = north(map); + _ = west(map); + _ = south(map); + return east(map); +} + +const MapCtx = struct { + pub fn hash(_: @This(), map: []const []u8) u64 { + var h: u64 = 0; + + for (map, 0..) |row, i| { + for (row, 0..) |c, j| { + if (c == 'O') { + h ^= @shlExact(i, 16) | (j); + } + } + } + h *= 1231231557; + h ^= (h >> 32); + return h; + } + + pub fn eql(_: @This(), lhs: []const []u8, rhs: []const []u8) bool { + for (lhs, rhs) |l, r| { + if (!mem.eql(u8, l, r)) { + return false; + } + } + + return true; + } +}; + +fn mapdup(map: []const []const u8) Map { + const h = map.len; + const w = map[0].len; + const new = allocator.alloc([]u8, h) catch unreachable; + + for (new, map) |*row, srcrow| { + row.* = allocator.alloc(u8, w) catch unreachable; + @memcpy(row.*, srcrow); + } + + return new; +} + +fn part1(map: []const []const u8) void { + const ans = north(mapdup(map)); + + print("{d}\n", .{ans}); +} + +fn part2(map_: []const []const u8) void { + var ans: u64 = 0; + var visited = HashMap(Map, u64, MapCtx, 80).init(allocator); + const map = mapdup(map_); + const reps = 1_000_000_000; + var upto: u64 = 0; + + for (0..reps) |p| { + ans = round(map); + if (visited.get(map)) |s| { + const start = s; + const period = p - s; + upto = (reps - start - 1) % period; + break; + } + visited.put(mapdup(map), p) catch unreachable; + } + + for (0..upto) |_| { + ans = round(map); + } + + print("{d}\n", .{ans}); +} + +pub fn solve(map: []const []const u8) void { + part1(map); + part2(map); +} + +pub fn main() !void { + var splitLines = mem.splitScalar(u8, fin, '\n'); + var map = ArrayList([]const u8).init(allocator); + + while (splitLines.next()) |line| { + try map.append(line); + } + + solve(map.items); +} -- cgit v1.2.3