const std = @import("std"); const path = "data/day15/input.txt"; const RetType = u9; const grid_cols = 100; const grid_rows = 100; const GridValue = u4; const Grid = [grid_rows][grid_cols]GridValue; const Distance = [grid_rows][grid_cols]RetType; const Point = struct { row: usize, col: usize, cost: RetType, }; fn lowerThan(context: void, a: Point, b: Point) std.math.Order { _ = context; return std.math.order(a.cost, b.cost); } const Queue = std.PriorityQueue(Point, void, lowerThan); const directions = [4][2]i2{ .{ 0, 1 }, .{ 0, -1 }, .{ 1, 0 }, .{ -1, 0 }, }; fn parseInput() anyerror!Grid { const input = @embedFile(path); var lines = std.mem.tokenize(u8, input, "\n"); var ret: Grid = undefined; var row: usize = 0; while (lines.next()) |line| : (row += 1) { for (line) |_, col| { ret[row][col] = try std.fmt.parseUnsigned(GridValue, line[col .. col + 1], 10); } } return ret; } pub fn first(allocator: ?std.mem.Allocator) anyerror!RetType { const g = try parseInput(); var distance = [_][grid_cols]RetType{[_]RetType{~@as(RetType, 0)} ** grid_cols} ** grid_rows; distance[0][0] = 0; var queue = Queue.init(allocator.?, {}); defer queue.deinit(); // add starting item to the queue try queue.add(Point{ .row = 0, .col = 0, .cost = 0 }); while (true) { var ret = try dijkstra(&g, &distance, &queue); if (ret != null) return ret.?; // XXX: distance grid is not finalized! } unreachable; } fn dijkstra(grid: *const Grid, dist: *Distance, queue: *Queue) !?RetType { const curr = queue.remove(); // std.debug.print("D: {d} {d} -> {d}\n", .{curr.row, curr.col, curr.cost}); if (curr.row == grid_rows - 1 and curr.col == grid_cols - 1) return curr.cost; for (directions) |dir| { const diffrow = @intCast(isize, curr.row) + dir[0]; if (diffrow < 0 or diffrow >= grid_rows) continue; const dr = @intCast(usize, diffrow); const diffcol = @intCast(isize, curr.col) + dir[1]; if (diffcol < 0 or diffcol >= grid_cols) continue; const dc = @intCast(usize, diffcol); const d = dist[curr.row][curr.col] + grid[dr][dc]; if (d < dist[dr][dc]) { try queue.add(Point{ .row = dr, .col = dc, .cost = d }); // queue.update( // Point{ .row = dr, .col = dc, .cost = dist[dr][dc] }, // Point{ .row = dr, .col = dc, .cost = d }, // ) catch |err| switch (err) { // error.ElementNotFound => try queue.add(Point{ .row = dr, .col = dc, .cost = d }), // else => return err, // }; dist[dr][dc] = d; } } return null; } pub fn main() anyerror!void { var buf: [10_000]u8 = undefined; var fba = std.heap.FixedBufferAllocator.init(&buf); var timer = try std.time.Timer.start(); const ret = try first(fba.allocator()); const t = timer.lap() / 1000; try std.testing.expectEqual(@as(RetType, 366), ret); std.debug.print("Day 15a result: {d} \t\ttime: {d}us\n", .{ ret, t }); } test "day15a" { try std.testing.expectEqual(@as(RetType, 366), try first(std.testing.allocator)); }