an attempt was made at part 2 day 23

This commit is contained in:
2024-10-12 16:43:04 +01:00
parent 72b3bf8231
commit 53da4d0bb2
3 changed files with 232 additions and 102 deletions

View File

@ -17,18 +17,11 @@ pub fn build(b: *std.Build) void {
const exe = b.addExecutable(.{
.name = "AdventOfCode2023",
// In this case the main source file is merely a path, however, in more
// complicated build scripts, this could be a generated file.
.root_source_file = .{ .path = "src/main.zig" },
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
});
const utils_module = b.createModule(.{
.source_file = .{ .path = "src/utils.zig" },
});
exe.addModule("utils", utils_module);
// This declares intent for the executable to be installed into the
// standard location when the user invokes the "install" step (the default
// step when running `zig build`).
@ -60,7 +53,7 @@ pub fn build(b: *std.Build) void {
// Creates a step for unit testing. This only builds the test executable
// but does not run it.
const unit_tests = b.addTest(.{
.root_source_file = .{ .path = "src/main.zig" },
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
});

View File

@ -43,22 +43,6 @@ pub fn Queue(comptime Child: type) type {
};
}
test "Hash maps as refs" {
var allocator = std.heap.page_allocator;
var q = Queue(*std.AutoHashMap(u128, bool)).init(allocator);
var m = std.AutoHashMap(u128, bool).init(allocator);
try m.put(0, true);
try m.put(1, true);
try expect(m.count() == 2);
try q.enqueue(&m);
var mPointer: *std.AutoHashMap(u128, bool) = q.dequeue().?;
try expect(mPointer.*.count() == 2);
}
fn coord(myX: usize, myY: usize) u128 {
return @as(u128, myX) << 64 | @as(u128, myY);
}
@ -94,15 +78,6 @@ fn isStep(s: u8, want: u8) bool {
return want == s;
}
// const Edge = struct {
// weight: usize,
// node: *Node,
// };
//
// const Node = struct {
// edges: []?Edge,
// };
fn bfs(grid: [][]const u8, goal: u128, explored: *std.AutoHashMap(u128, bool), root: u128, allocator: std.mem.Allocator, part2: bool) !usize {
var q = Queue(u128).init(allocator);
var qLength = Queue(usize).init(allocator);
@ -126,42 +101,41 @@ fn bfs(grid: [][]const u8, goal: u128, explored: *std.AutoHashMap(u128, bool), r
var part1: usize = 0;
while (q.dequeue()) |c| {
var child: u128 = c;
var size: usize = qLength.dequeue().?;
var paths: []u128 = qPaths.dequeue().?;
const child: u128 = c;
const size: usize = qLength.dequeue().?;
const paths: []u128 = qPaths.dequeue().?;
if (child == goal) {
// don't return, because we need all routes.
print("Size: {}\n", .{size + 1});
part1 = size + 1;
continue;
}
var up = child - 1;
var upX = x(up);
var upY = y(up);
const up = child - 1;
const upX = x(up);
const upY = y(up);
var down = child + 1;
var downX = x(down);
var downY = y(down);
const down = child + 1;
const downX = x(down);
const downY = y(down);
var right = child + (@as(u128, 1) << 64);
var rightX = x(right);
var rightY = y(right);
const right = child + (@as(u128, 1) << 64);
const rightX = x(right);
const rightY = y(right);
var left = child - (@as(u128, 1) << 64);
var leftX = x(left);
var leftY = y(left);
const left = child - (@as(u128, 1) << 64);
const leftX = x(left);
const leftY = y(left);
var lastStep = paths[paths.len - 1];
var lastStepX = x(lastStep);
var lastStepY = y(lastStep);
const lastStep = paths[paths.len - 1];
const lastStepX = x(lastStep);
const lastStepY = y(lastStep);
var l = grid[lastStepY][lastStepX];
if (part2) {
l = '.';
}
if (!linear_search(paths, up) and grid[upY][upX] != WALL and isStep(l, '^')) {
if (grid[upY][upX] != WALL and isStep(l, '^') and !linear_search(paths, up)) {
var pathsCopy = try allocator.alloc(u128, paths.len + 1);
short_copy(pathsCopy, paths);
pathsCopy[pathsCopy.len - 1] = up;
@ -170,7 +144,8 @@ fn bfs(grid: [][]const u8, goal: u128, explored: *std.AutoHashMap(u128, bool), r
try qLength.enqueue(size + 1);
try qPaths.enqueue(pathsCopy);
}
if (!linear_search(paths, down) and grid[downY][downX] != WALL and isStep(l, 'v')) {
if (grid[downY][downX] != WALL and isStep(l, 'v') and !linear_search(paths, down)) {
var pathsCopy = try allocator.alloc(u128, paths.len + 1);
short_copy(pathsCopy, paths);
pathsCopy[pathsCopy.len - 1] = down;
@ -179,7 +154,8 @@ fn bfs(grid: [][]const u8, goal: u128, explored: *std.AutoHashMap(u128, bool), r
try qLength.enqueue(size + 1);
try qPaths.enqueue(pathsCopy);
}
if (!linear_search(paths, right) and grid[rightY][rightX] != WALL and isStep(l, '>')) {
if (grid[rightY][rightX] != WALL and isStep(l, '>') and !linear_search(paths, right)) {
var pathsCopy = try allocator.alloc(u128, paths.len + 1);
short_copy(pathsCopy, paths);
pathsCopy[pathsCopy.len - 1] = right;
@ -188,7 +164,8 @@ fn bfs(grid: [][]const u8, goal: u128, explored: *std.AutoHashMap(u128, bool), r
try qLength.enqueue(size + 1);
try qPaths.enqueue(pathsCopy);
}
if (!linear_search(paths, left) and grid[leftY][leftX] != WALL and isStep(l, '<')) {
if (grid[leftY][leftX] != WALL and isStep(l, '<') and !linear_search(paths, left)) {
var pathsCopy = try allocator.alloc(u128, paths.len + 1);
short_copy(pathsCopy, paths);
pathsCopy[pathsCopy.len - 1] = left;
@ -204,65 +181,225 @@ fn bfs(grid: [][]const u8, goal: u128, explored: *std.AutoHashMap(u128, bool), r
return part1;
}
fn dps(grid: [][]const u8, root: u128, goal: u128, explored: []u128, size: usize, allocator: std.mem.Allocator) !usize {
if (root == goal) {
print("Size: {}\n", .{size});
return size;
const Direction = enum { up, down, right, left };
fn num_of_non_wall(input: *const [][]const u8, coord1: u128, coord2: u128, coord3: u128, coord4: u128) u8 {
var counter: u8 = 0;
if (input.*[y(coord1)][x(coord1)] != WALL) {
counter += 1;
}
if (input.*[y(coord2)][x(coord2)] != WALL) {
counter += 1;
}
if (input.*[y(coord3)][x(coord3)] != WALL) {
counter += 1;
}
if (input.*[y(coord4)][x(coord4)] != WALL) {
counter += 1;
}
var up = root - 1;
var down = root + 1;
var right = root + (@as(u128, 1) << 64);
var left = root - (@as(u128, 1) << 64);
var neighbours = [_]u128{ up, down, right, left };
return counter;
}
var highest: usize = 0;
fn direction(input: *const [][]const u8, explored: *std.AutoHashMap(u128, bool), up: u128, down: u128, right: u128, left: u128) Direction {
if (explored.get(up) == null and input.*[y(up)][x(up)] != WALL) {
return Direction.up;
}
if (explored.get(down) == null and input.*[y(down)][x(down)] != WALL) {
return Direction.down;
}
if (explored.get(left) == null and input.*[y(left)][x(left)] != WALL) {
return Direction.left;
}
if (explored.get(right) == null and input.*[y(right)][x(right)] != WALL) {
return Direction.right;
}
for (neighbours) |n| {
var nx = x(n);
var ny = y(n);
if (!linear_search(explored, n) and grid[ny][nx] != WALL) {
var copyExplored = try allocator.alloc(u128, explored.len + 1);
short_copy(copyExplored, explored);
copyExplored[copyExplored.len - 1] = n;
var h = try dps(grid, n, goal, copyExplored, size + 1, allocator);
if (h > highest) {
highest = h;
unreachable;
}
const Edge = struct { distance: usize, to_x: usize, to_y: usize };
fn compress_graph(allocator: std.mem.Allocator, input: [][]const u8) !std.AutoHashMap(u128, []Edge) {
var nodes = std.ArrayList(u128).init(allocator);
defer nodes.deinit();
for (1..input.len - 1) |y_part| {
for (1..input[0].len - 1) |x_part| {
if (input[y_part][x_part] != '.') {
continue;
}
allocator.free(copyExplored);
const up = coord(x_part, y_part - 1);
const down = coord(x_part, y_part + 1);
const right = coord(x_part + 1, y_part);
const left = coord(x_part - 1, y_part);
const non_wall_count = num_of_non_wall(&input, up, down, right, left);
if (non_wall_count == 0 or non_wall_count == 1) {
unreachable;
}
if (non_wall_count == 2) {
if (input[y(up)][x(up)] != WALL and input[y(down)][x(down)] != WALL) {
continue;
}
if (input[y(left)][x(left)] != WALL and input[y(right)][x(right)] != WALL) {
continue;
}
}
try nodes.append(coord(x_part, y_part));
}
}
return highest;
var edges_map = std.AutoHashMap(u128, []Edge).init(allocator);
for (nodes.items) |a| {
lower: for (nodes.items) |b| {
if (a == b) {
continue;
}
if (x(a) == x(b)) {
// Check they can see each other.
const min_y = if (y(a) < y(b)) y(a) else y(b);
const max_y = if (y(a) > y(b)) y(a) else y(b);
const contains_walls = for (min_y..max_y) |counter_y| {
if (input[counter_y][x(a)] == WALL) {
break true;
}
} else false;
if (contains_walls) {
continue :lower;
}
const new_edge = Edge{ .to_x = x(b), .to_y = y(b), .distance = max_y - min_y };
if (edges_map.get(a)) |edges_arr| {
var new_edges_arr = try allocator.realloc(edges_arr, edges_arr.len + 1);
new_edges_arr[new_edges_arr.len - 1] = new_edge;
try edges_map.put(a, new_edges_arr);
} else {
var new_edges_arr = try allocator.alloc(Edge, 1);
new_edges_arr[0] = new_edge;
try edges_map.put(a, new_edges_arr);
}
}
if (y(a) == y(b)) {
// Check they can see each other.
const min_x = if (x(a) < x(b)) x(a) else x(b);
const max_x = if (x(a) > x(b)) x(a) else x(b);
const contains_walls = for (min_x..max_x) |counter_x| {
if (input[y(a)][counter_x] == WALL) {
break true;
}
} else false;
if (contains_walls) {
continue :lower;
}
const new_edge = Edge{ .to_x = x(b), .to_y = y(b), .distance = max_x - min_x };
if (edges_map.get(a)) |edges_arr| {
var new_edges_arr = try allocator.realloc(edges_arr, edges_arr.len + 1);
new_edges_arr[new_edges_arr.len - 1] = new_edge;
try edges_map.put(a, new_edges_arr);
} else {
var new_edges_arr = try allocator.alloc(Edge, 1);
new_edges_arr[0] = new_edge;
try edges_map.put(a, new_edges_arr);
}
}
}
}
return edges_map;
}
fn includes(nodes: []u128, node: u128) bool {
for (nodes) |n| {
if (n == node) {
return true;
}
}
return false;
}
fn dfs(allocator: std.mem.Allocator, edges_map: std.AutoHashMap(u128, []Edge), end: u128) !usize {
var stack = std.ArrayList(u128).init(allocator);
var stack_distance = std.ArrayList(usize).init(allocator);
var stack_explored = std.ArrayList([]u128).init(allocator);
defer stack.deinit();
defer stack_distance.deinit();
defer stack_explored.deinit();
const initial_explored = try allocator.alloc(u128, 0);
try stack.append(coord(1, 1));
try stack_distance.append(2);
try stack_explored.append(initial_explored);
var longest_distance: usize = 0;
while (stack.items.len > 0) {
const popped_node = stack.pop();
const popped_distance = stack_distance.pop();
const popped_explored = stack_explored.pop();
defer allocator.free(popped_explored);
if (includes(popped_explored, popped_node)) {
continue;
}
if (popped_node == end and popped_distance > longest_distance) {
longest_distance = popped_distance;
}
const edges = edges_map.get(popped_node).?;
for (edges) |edge| {
var copied_edges = try allocator.alloc(u128, popped_explored.len + 1);
std.mem.copyForwards(u128, copied_edges, popped_explored);
copied_edges[copied_edges.len - 1] = popped_node;
try stack.append(coord(edge.to_x, edge.to_y));
try stack_distance.append(popped_distance + edge.distance);
try stack_explored.append(copied_edges);
}
}
return longest_distance;
}
pub fn solve(input: [][]const u8) !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
var allocator = gpa.allocator();
const allocator = gpa.allocator();
var explored = std.AutoHashMap(u128, bool).init(allocator);
var start = coord(1, 0);
const start = coord(1, 0);
try explored.put(start, true);
var fakeStart = coord(1, 1);
const goal = coord(input[0].len - 2, input.len - 2);
var goal = coord(input[0].len - 2, input.len - 1);
_ = goal;
// var part1 = try bfs(input, goal, &explored, fakeStart, allocator, false);
// const part1 = try bfs(input, goal, &explored, fakeStart, allocator, false);
// print("Part 1: {}\n", .{part1});
// var part2 = try bfs(input, goal, &explored, fakeStart, allocator, true);
// print("Part 2: {}\n", .{part2});
var exp = try allocator.alloc(u128, 1);
exp[0] = start;
// var exampleLastInter = coord(19, 20);
var exampleLastInter = coord(133, 137);
var part2 = try dps(input, fakeStart, exampleLastInter, exp, 0, allocator);
print("Part 2: {}\n", .{part2 + 21});
const edges = try compress_graph(allocator, input);
const part2 = try dfs(allocator, edges, goal);
print("Part 2: {}\n", .{part2});
}

View File

@ -19,15 +19,15 @@ const std = @import("std");
// const day19 = @import("./day19/day19.zig");
// const day20 = @import("./day20/day20.zig");
// const day21 = @import("./day21/day21.zig");
const day22 = @import("./day22/day22.zig");
// const day23 = @import("./day23/day23.zig");
// const day22 = @import("./day22/day22.zig");
const day23 = @import("./day23/day23.zig");
// const day24 = @import("./day24/day24.zig");
const utils = @import("utils.zig");
pub fn main() !void {
const allocator = std.heap.page_allocator;
const input = try utils.getInput("./src/day22/input.txt", allocator);
const input = try utils.getInput("./src/day23/input.txt", allocator);
defer allocator.free(input);
try day22.solve(input);
try day23.solve(input);
}