Solve day 12

This commit is contained in:
Tyler Hallada 2022-12-12 23:46:40 -05:00
parent f65eeaa7ff
commit 8cca642364
3 changed files with 182 additions and 0 deletions

174
src/day12.zig Normal file
View File

@ -0,0 +1,174 @@
const std = @import("std");
pub const input = @embedFile("input/day12.txt");
const test_input1 = @embedFile("input/day12_test1.txt");
var gpa = std.heap.GeneralPurposeAllocator(.{ .safety = true }){};
const allocator = gpa.allocator();
const MAX_X = 159;
const MAX_Y = 41;
const PathNode = struct {
position: [2]u8,
f_score: usize,
g_score: usize,
parent: ?*PathNode,
};
fn h_score(a: [2]u8, b: [2]u8) !usize {
return std.math.sqrt(std.math.pow(usize, @intCast(usize, try std.math.absInt(@intCast(i16, a[0]) - @intCast(i16, b[0]))), 2) +
std.math.pow(usize, @intCast(usize, try std.math.absInt(@intCast(i16, a[1]) - @intCast(i16, b[1]))), 2));
}
fn lowest_f(context: void, a: *PathNode, b: *PathNode) std.math.Order {
_ = context;
return std.math.order(a.f_score, b.f_score);
}
const Grid = struct {
grid: [MAX_Y][MAX_X]u8,
max_x: usize,
max_y: usize,
start: [2]u8,
end: [2]u8,
fn new() Grid {
return Grid{ .grid = [_][MAX_X]u8{[_]u8{0} ** MAX_X} ** MAX_Y, .max_x = MAX_X, .max_y = MAX_Y, .start = [2]u8{ 0, 0 }, .end = [2]u8{ 0, 0 } };
}
fn parse(data: []const u8) !Grid {
var grid = Grid.new();
var lines = std.mem.tokenize(u8, data, "\n");
var y: u8 = 0;
while (lines.next()) |line| : (y += 1) {
var x: u8 = 0;
grid.max_x = line.len;
while (x < line.len) : (x += 1) {
var height = line[x];
if (height == 'S') {
grid.start = [2]u8{ y, x };
height = 'a';
} else if (height == 'E') {
grid.end = [2]u8{ y, x };
height = 'z';
}
grid.grid[y][x] = height;
}
}
grid.max_y = y;
return grid;
}
fn a_star(self: Grid) !usize {
var open_list = std.PriorityQueue(*PathNode, void, lowest_f).init(allocator, {});
var open_g_scores = std.AutoHashMap([2]u8, usize).init(allocator);
var closed_list = std.AutoHashMap([2]u8, void).init(allocator);
var start = try allocator.create(PathNode);
start.* = PathNode{ .position = self.start, .g_score = 0, .f_score = 0, .parent = null };
try open_list.add(start);
while (open_list.count() != 0) {
var current_node = open_list.remove();
var current = current_node.position;
_ = open_g_scores.remove(current);
var current_height = self.grid[current[0]][current[1]];
try closed_list.put(current, {});
if (std.mem.eql(u8, &current, &self.end)) {
// try self.print_path(current_node);
return current_node.g_score;
}
const neighbors = [4][2]i16{
[2]i16{ -1, 0 },
[2]i16{ 1, 0 },
[2]i16{ 0, -1 },
[2]i16{ 0, 1 },
};
var i: u8 = 0;
while (i < neighbors.len) : (i += 1) {
if ((neighbors[i][0] == -1 and current[0] > 0) or
(neighbors[i][0] == 1 and current[0] < MAX_Y - 1) or
(neighbors[i][1] == -1 and current[1] > 0) or
(neighbors[i][1] == 1 and current[1] < MAX_X - 1))
{
var neighbor = [2]u8{ @intCast(u8, @intCast(i16, current[0]) + neighbors[i][0]), @intCast(u8, @intCast(i16, current[1]) + neighbors[i][1]) };
if (!closed_list.contains(neighbor) and self.grid[neighbor[0]][neighbor[1]] <= current_height + 1) {
var g = current_node.g_score + 1;
if (!open_g_scores.contains(neighbor) or open_g_scores.get(neighbor).? < g) {
var h = try h_score(neighbor, self.end);
var f = g + h;
var node = try allocator.create(PathNode);
node.* = PathNode{ .position = neighbor, .g_score = g, .f_score = f, .parent = current_node };
try open_list.add(node);
try open_g_scores.put(neighbor, g);
}
}
}
}
}
return 0;
}
fn print_path(self: Grid, end_node: *PathNode) !void {
var path = std.AutoHashMap([2]u8, u8).init(allocator);
var node = end_node;
while (node.parent) |parent| {
var char: u8 = '#';
if (node.position[0] < parent.position[0]) {
char = '^';
} else if (node.position[0] > parent.position[0]) {
char = 'v';
} else if (node.position[1] < parent.position[1]) {
char = '<';
} else if (node.position[1] > parent.position[1]) {
char = '>';
}
try path.put(node.position, char);
node = parent;
}
var y: u8 = 0;
while (y < MAX_Y) : (y += 1) {
var x: u8 = 0;
while (x < MAX_X) : (x += 1) {
var char = self.grid[y][x];
if (path.get([2]u8{ y, x })) |path_char| {
char = path_char;
}
std.debug.print("{s}", .{[_]u8{char}});
}
std.debug.print("\n", .{});
}
}
};
pub fn solve_part1(data: []const u8) !usize {
var grid = try Grid.parse(data);
return grid.a_star();
}
pub fn solve_part2(data: []const u8) !usize {
var grid = try Grid.parse(data);
var min_score: ?usize = null;
var y: u8 = 0;
while (y < grid.max_y) : (y += 1) {
grid.start = [2]u8{ y, 0 };
const score = try grid.a_star();
if (min_score) |min| {
if (score < min) {
min_score = score;
}
} else {
min_score = score;
}
}
return min_score.?;
}
test "solves part1" {
try std.testing.expectEqual(solve_part1(test_input1), 31);
}
test "solves part2" {
try std.testing.expectEqual(solve_part2(test_input1), 29);
}

View File

@ -0,0 +1,5 @@
Sabqponm
abcryxxl
accszExk
acctuvwj
abdefghi

View File

@ -11,6 +11,7 @@ const day08 = @import("day08.zig");
const day09 = @import("day09.zig"); const day09 = @import("day09.zig");
const day10 = @import("day10.zig"); const day10 = @import("day10.zig");
const day11 = @import("day11.zig"); const day11 = @import("day11.zig");
const day12 = @import("day12.zig");
const utils = @import("utils.zig"); const utils = @import("utils.zig");
fn solve_day(comptime day_num: u8, day: anytype, stdout: anytype, timer: *std.time.Timer) !void { fn solve_day(comptime day_num: u8, day: anytype, stdout: anytype, timer: *std.time.Timer) !void {
@ -54,6 +55,7 @@ pub fn main() !void {
try solve_day(9, day09, &stdout, &timer); try solve_day(9, day09, &stdout, &timer);
try solve_day(10, day10, &stdout, &timer); try solve_day(10, day10, &stdout, &timer);
try solve_day(11, day11, &stdout, &timer); try solve_day(11, day11, &stdout, &timer);
try solve_day(12, day12, &stdout, &timer);
try bw.flush(); try bw.flush();
} }
@ -72,5 +74,6 @@ test {
_ = day09; _ = day09;
_ = day10; _ = day10;
_ = day11; _ = day11;
_ = day12;
_ = utils; _ = utils;
} }