day 18, part 1 (improved in preparation to part 2)

main
Inga 🏳‍🌈 10 months ago
parent e2836d4266
commit 322b8b7113
  1. 139
      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;

Loading…
Cancel
Save