an attempt was made at part 2 day 23
This commit is contained in:
@ -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,
|
||||
});
|
||||
|
@ -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});
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
Reference in New Issue
Block a user