From 322b8b71130b65631426345c122b7665d246a767 Mon Sep 17 00:00:00 2001 From: Inga Date: Sun, 7 Jan 2024 16:48:54 +0000 Subject: [PATCH] day 18, part 1 (improved in preparation to part 2) --- day18-easy/src/main.zig | 139 +++++++++++++++++++++++++++++++++------- 1 file changed, 116 insertions(+), 23 deletions(-) diff --git a/day18-easy/src/main.zig b/day18-easy/src/main.zig index 9a1c8f7..499b8be 100644 --- a/day18-easy/src/main.zig +++ b/day18-easy/src/main.zig @@ -1,5 +1,49 @@ const std = @import("std"); +fn StackList(comptime T: type, comptime capacity_type: type, comptime capacity: capacity_type) type { + return struct { + const Self = @This(); + mem: [capacity]T, + length: capacity_type, + + fn add(self: *Self, value: T) void { + self.mem[self.length] = value; + self.length += 1; + } + + fn addIfNotNull(self: *Self, nullable_value: ?T) void { + if (nullable_value) |value| { + self.add(value); + } + } + + fn has(self: *Self, needle: T) bool { + for (0..self.length) |i| { + if (self.mem[i] == needle) { + return true; + } + } + + return false; + } + + fn getMutableSlice(self: *Self) []T { + return (&self.mem)[0..self.length]; + } + + fn getSlice(self: *const Self) []const T { + return self.mem[0..self.length]; + } + + fn init() Self { + return Self{ + .mem = undefined, + .length = 0, + }; + } + }; +} + fn RingQueueWrapper(comptime T: type, comptime size: usize) type { return struct { const Self = @This(); @@ -87,6 +131,18 @@ const FloodTask = struct { y: TerrainCoordinate, }; +const Direction = enum(u8) { + Right = 0, + Down = 1, + Left = 2, + Up = 3, +}; + +const Command = packed struct(u32) { + direction: Direction, + length: u24, +}; + fn floodTerrain(terrain: *Terrain) void { var queue_mem: [65_536]FloodTask = undefined; var tasks = RingQueueWrapper(FloodTask, queue_mem.len).init(&queue_mem); @@ -138,34 +194,71 @@ fn solveForTerrain(terrain: *Terrain) usize { return result; } -fn dig(terrain: *Terrain, command: []const u8) void { - var index: usize = 2; - const length = readNumber(usize, command, &index); - const direction = command[0]; - - for (0..length) |i| { - _ = i; - terrain.*.x = switch (direction) { - 'R' => terrain.*.x + 1, - 'L' => terrain.*.x - 1, - else => terrain.*.x, - }; - - terrain.*.y = switch (direction) { - 'D' => terrain.*.y + 1, - 'U' => terrain.*.y - 1, - else => terrain.*.y, - }; - - //std.debug.print("digging {d},{d}\n", .{ terrain.*.x, terrain.*.y }); +fn dig(terrain: *Terrain, command: Command) void { + const target_x = switch (command.direction) { + .Right => terrain.*.x + command.length, + .Left => terrain.*.x - command.length, + .Up, .Down => terrain.*.x, + }; + + const target_y = switch (command.direction) { + .Down => terrain.*.y + command.length, + .Up => terrain.*.y - command.length, + .Left, .Right => terrain.*.y, + }; + + while (terrain.*.x != target_x) { + if (terrain.*.x < target_x) { + terrain.*.x += 1; + } else { + terrain.*.x -= 1; + } + terrain.*.cells[terrain.*.x][terrain.*.y] = .Dug; } + + while (terrain.*.y != target_y) { + if (terrain.*.y < target_y) { + terrain.*.y += 1; + } else { + terrain.*.y -= 1; + } + + terrain.*.cells[terrain.*.x][terrain.*.y] = .Dug; + } +} + +fn parseCommand(command: []const u8) Command { + var index: usize = 2; + const length = readNumber(u24, command, &index); + const direction: Direction = switch (command[0]) { + 'R' => .Right, + 'L' => .Left, + 'U' => .Up, + 'D' => .Down, + else => unreachable, + }; + + return .{ + .length = length, + .direction = direction, + }; +} + +fn solveForCommands(commands: []const Command) usize { + var terrain = Terrain.initZeroes(); + + for (commands) |command| { + dig(&terrain, command); + } + + return solveForTerrain(&terrain); } fn solveAll(reader: anytype) !usize { var result: usize = 0; while (true) { - var terrain = Terrain.initZeroes(); + var commands = StackList(Command, usize, 1024).init(); var empty_line_reached = false; var line_buffer: [1000]u8 = undefined; @@ -174,10 +267,10 @@ fn solveAll(reader: anytype) !usize { empty_line_reached = true; break; } - dig(&terrain, line); + commands.add(parseCommand(line)); } - result += solveForTerrain(&terrain); + result += solveForCommands(commands.getSlice()); if (!empty_line_reached) { return result;