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

main
Inga 🏳‍🌈 12 months ago
parent 322b8b7113
commit dba2aeadc8
  1. 119
      day18-easy/src/main.zig

@ -104,14 +104,59 @@ fn readNumber(comptime T: type, line: []const u8, index: *usize) T {
return if (is_negative) (0 - result) else result; return if (is_negative) (0 - result) else result;
} }
fn GenericTerrain(comptime CoordinateType: type, comptime height: CoordinateType, comptime width: CoordinateType, comptime CellType: type) type { fn Coordinates(comptime CoordinateType: type) type {
return struct { return struct {
const Self = @This(); const Self = @This();
x: CoordinateType, x: CoordinateType,
y: CoordinateType, y: CoordinateType,
fn isSameX(self: *const Self, other: Self) bool {
return self.x == other.x;
}
fn approachX(self: *Self, other: Self) void {
if (self.x < other.x) {
self.x += 1;
} else {
self.x -= 1;
}
}
fn isSameY(self: *const Self, other: Self) bool {
return self.y == other.y;
}
fn approachY(self: *Self, other: Self) void {
if (self.y < other.y) {
self.y += 1;
} else {
self.y -= 1;
}
}
};
}
fn GenericTerrain(comptime CoordinateType: type, comptime height: CoordinateType, comptime width: CoordinateType, comptime CellType: type) type {
return struct {
const Self = @This();
coordinates: Coordinates(CoordinateType),
cells: [height][width]CellType, cells: [height][width]CellType,
fn initZeroes() Self { fn initZeroes() Self {
return .{ .x = height / 2, .y = width / 2, .cells = std.mem.zeroes([height][width]CellType) }; return .{
.coordinates = .{
.x = height / 2,
.y = width / 2,
},
.cells = std.mem.zeroes([height][width]CellType),
};
}
fn getCurrentCell(self: *const Self) CellType {
return self.cells[self.coordinates.x][self.coordinates.y];
}
fn setCurrentCell(self: *Self, value: CellType) void {
self.cells[self.coordinates.x][self.coordinates.y] = value;
} }
}; };
} }
@ -126,10 +171,7 @@ const TerrainCoordinate = u16;
const Terrain = GenericTerrain(TerrainCoordinate, 1024, 1024, CellStatus); const Terrain = GenericTerrain(TerrainCoordinate, 1024, 1024, CellStatus);
const FloodTask = struct { const TerrainCoordinates = Coordinates(TerrainCoordinate);
x: TerrainCoordinate,
y: TerrainCoordinate,
};
const Direction = enum(u8) { const Direction = enum(u8) {
Right = 0, Right = 0,
@ -140,24 +182,26 @@ const Direction = enum(u8) {
const Command = packed struct(u32) { const Command = packed struct(u32) {
direction: Direction, direction: Direction,
length: u24, _: u8 = 0,
length: u16,
}; };
fn floodTerrain(terrain: *Terrain) void { fn floodTerrain(terrain: *Terrain) void {
var queue_mem: [65_536]FloodTask = undefined; var queue_mem: [65_536]TerrainCoordinates = undefined;
var tasks = RingQueueWrapper(FloodTask, queue_mem.len).init(&queue_mem); var tasks = RingQueueWrapper(TerrainCoordinates, queue_mem.len).init(&queue_mem);
tasks.add(.{ .x = 0, .y = 0 }); tasks.add(.{ .x = 0, .y = 0 });
while (!tasks.isEmpty()) { while (!tasks.isEmpty()) {
const task = tasks.take(); const task = tasks.take();
const x = task.x; terrain.coordinates = task;
const y = task.y;
//std.debug.print("Processing task for {d},{d} (current status: {any})\n", .{ x, y, terrain.*.cells[x][y] }); //std.debug.print("Processing task for {d},{d} (current status: {any})\n", .{ x, y, terrain.*.cells[x][y] });
if (terrain.*.cells[x][y] == .Default) { if (terrain.getCurrentCell() == .Default) {
terrain.*.cells[x][y] = .NotDug; terrain.setCurrentCell(.NotDug);
//std.debug.print("Marked {d},{d} as NotDug\n", .{ x, y }); //std.debug.print("Marked {d},{d} as NotDug\n", .{ x, y });
const x = task.x;
const y = task.y;
if (x > 0) { if (x > 0) {
tasks.add(.{ .x = x - 1, .y = y }); tasks.add(.{ .x = x - 1, .y = y });
} }
@ -194,43 +238,38 @@ fn solveForTerrain(terrain: *Terrain) usize {
return result; return result;
} }
fn dig(terrain: *Terrain, command: Command) void { fn getTargetCoordinates(coordinates: TerrainCoordinates, command: Command) TerrainCoordinates {
const target_x = switch (command.direction) { return .{
.Right => terrain.*.x + command.length, .x = switch (command.direction) {
.Left => terrain.*.x - command.length, .Right => coordinates.x + command.length,
.Up, .Down => terrain.*.x, .Left => coordinates.x - command.length,
}; .Up, .Down => coordinates.x,
},
const target_y = switch (command.direction) { .y = switch (command.direction) {
.Down => terrain.*.y + command.length, .Down => coordinates.y + command.length,
.Up => terrain.*.y - command.length, .Up => coordinates.y - command.length,
.Left, .Right => terrain.*.y, .Left, .Right => coordinates.y,
},
}; };
}
while (terrain.*.x != target_x) { fn dig(terrain: *Terrain, command: Command) void {
if (terrain.*.x < target_x) { const target = getTargetCoordinates(terrain.*.coordinates, command);
terrain.*.x += 1;
} else {
terrain.*.x -= 1;
}
terrain.*.cells[terrain.*.x][terrain.*.y] = .Dug;
}
while (terrain.*.y != target_y) { while (!terrain.*.coordinates.isSameX(target)) {
if (terrain.*.y < target_y) { terrain.*.coordinates.approachX(target);
terrain.*.y += 1; terrain.*.setCurrentCell(.Dug);
} else {
terrain.*.y -= 1;
} }
terrain.*.cells[terrain.*.x][terrain.*.y] = .Dug; while (!terrain.*.coordinates.isSameY(target)) {
terrain.*.coordinates.approachY(target);
terrain.*.setCurrentCell(.Dug);
} }
} }
fn parseCommand(command: []const u8) Command { fn parseCommand(command: []const u8) Command {
var index: usize = 2; var index: usize = 2;
const length = readNumber(u24, command, &index); const length = readNumber(u16, command, &index);
const direction: Direction = switch (command[0]) { const direction: Direction = switch (command[0]) {
'R' => .Right, 'R' => .Right,
'L' => .Left, 'L' => .Left,

Loading…
Cancel
Save