aoc/2021/15/src/main.zig

136 lines
3.9 KiB
Zig

const std = @import("std");
pub fn main() anyerror!void {
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
const alloc = arena.allocator();
// Read our input
var f = try std.fs.cwd().openFile("input", .{});
defer f.close();
var contents = try f.readToEndAlloc(alloc, std.math.maxInt(u32));
defer alloc.free(contents);
var it = std.mem.tokenize(u8, contents, "\n");
var map = std.ArrayList(u8).init(alloc);
defer map.deinit();
var width: u8 = 0;
var height: u8 = 0;
while (it.next()) |line| {
height += 1;
if (@intCast(u8, line.len) > width) {
width = @intCast(u8, line.len);
}
for (line) |_, i| {
try map.append(try std.fmt.parseInt(u8, line[i..i+1], 10));
}
}
var path = try find_path(alloc, map.items, width, height);
defer path.deinit();
}
const Point = struct {
x: u8 = 0,
y: u8 = 0,
pub fn get_index(p: *Point, width: u8, height: u8) usize {
_ = width;
return @as(usize, height) * @as(usize, p.y) + @as(usize, p.x);
}
pub fn from_index(index: usize, width: u8, height: u8) Point {
return Point {
.x = @intCast(u8, index % width),
.y = @intCast(u8, index / height),
};
}
};
fn find_path(alloc: std.mem.Allocator, map: []u8, width: u8,
height: u8) !std.ArrayList(Point) {
var path = std.ArrayList(Point).init(alloc);
var open_set = std.AutoHashMap(Point, void).init(alloc);
defer open_set.deinit();
// Our starting point
try open_set.put(.{.x = width - 1, .y = height - 1}, undefined);
var came_from = std.AutoHashMap(Point, void).init(alloc);
defer came_from.deinit();
while (open_set.count() > 0) {
// Find lowest score in openset
var lowest: Point = undefined;
var score: u8 = std.math.maxInt(u8);
var oit = open_set.iterator();
while(oit.next()) |kv| {
var p = kv.key_ptr.*;
_ = kv.value_ptr.*;
// We might have to modify this, since our open_set may
// contain points that aren't directly adjacent?
if (map[p.get_index(width, height)] < score) {
lowest = p;
score = map[p.get_index(width, height)];
}
}
std.log.debug("Went to point {}, {}: score {}",
.{lowest.x, lowest.y, score});
try path.append(lowest);
try came_from.put(lowest, undefined);
if (lowest.x == 0 and lowest.y == 0) {
// We have arrived
return path;
}
_ = open_set.remove(lowest);
// Let's clear our open_set, but this might be an error
open_set.clearRetainingCapacity();
var adjacents = get_adjacent_points(lowest.get_index(width, height),
width, height);
for (adjacents) |adj| {
if (adj) |a| {
var p = Point.from_index(a, width, height);
if (came_from.contains(p)) {
continue;
}
try open_set.put(p, undefined);
}
}
}
// Failure to find path
unreachable;
}
fn get_adjacent_points(i: usize, width: usize, height: usize) [4]?usize {
var adjacents = [4] ?usize {
null,
null,
null,
null,
};
var ai: usize = 0;
var bottom = i < ((height - 1) * width);
var top = i >= width;
var left = (i % width) != 0;
var right = (i % width) != (width - 1);
if (top) {
adjacents[ai] = i - width;
ai += 1;
}
if (left) {
adjacents[ai] = i - 1;
ai += 1;
}
if (right) {
adjacents[ai] = i + 1;
ai += 1;
}
if (bottom) {
adjacents[ai] = i + width;
ai += 1;
}
return adjacents;
}