~andreafeletto/advent

a98e7d425d578cffd286ff38ddde3308cbbd0d9d — Andrea Feletto 1 year, 8 months ago 4d3f031
year 2022 day 12
3 files changed, 232 insertions(+), 0 deletions(-)

A 2022/12/input
A 2022/12/solve.zig
M build.zig
A 2022/12/input => 2022/12/input +41 -0
@@ 0,0 1,41 @@
abcccccccccccccccccccccccccccccccccccccaaaaaaacccccccaaaaaaaaaaaccccccccccccccccccccaaacaaaaaaaacccccccccccccccccccccccccccccccccccaaaaa
abccccccccccccccccccaaccaacccccccccccccaaaaaaaccccccccaaaaaaaaaaacccccccaaaaccccccccaaaaaaaaaaaaacccccccccccccccccccccccccccccccccaaaaaa
abccccccccccccccccccaaaaaaccccccccccaaaccaaaaaacccccccaaaaaaaaaaccccccccaaaaccccccaaaaaaaaaaaaaaacccccccccccccccccccaaacccccccccccaaaaaa
abcccccccccccccccccccaaaaacccccccccccaaccaacaaaccccccaaaaaaaaaaaccccccccaaaacccccaaaaaaaaacaaaaaaacccccccccccccccccaaaacccccccccccaaacaa
abccccccccccccccccccaaaaaaccccccccaacaaaaaacccccccccaaaaaaaaaaaaacaaaccccaaccccccaaaaaaaaacaacccccccccccccccccaaaccaaaacccccccccccccccaa
abcccccccccccccccccaaaaaaaacccccccaaaaaaaaccccccaaaaaaaacaaaacaaaaaaacccccccccaaccccaaaaaacaaacccccccccccccccaaaakkkaaccccccccccccccccaa
abcccccccccccccccccaaaaaaaaccccccccaaaaaccccaacccaaaaaaaaaaaacaaaaaaccccccccccaacccaaaaaaaaaaaacccccccccccccccakkkkkklcccccccccccccccccc
abaaacccccccccccaaccccaaccccccccccccaaaaaccaaacccaaaaaaaaaaaaaaaaaaaaccccccaaaaaaaacaacccaaaaaaccccccccccccccckkkkkkkllcccccccaaaccccccc
abaaaacccccccaacaaccccaacccccccccccaaacaaaaaaaccccaaaaaaaaaaaaaaaaaaaacccccaaaaaaaaaaaccccaaaaacccccccccccccckkkksssllllccccccaaaaaacccc
abaaaacccccccaaaaacccccccccccaaaccccaacaaaaaaccccaaaaaacaaaaaaaaaaaaaacccccccaaaaccccccccaaaaacccccccccccccckkkksssssllllcccccaaaaaacccc
abaaacccccccccaaaaaaccccccccaaaaccccccccaaaaaaaacaaaaaaaaaaaaacaaacaaacccccccaaaaacccccccaaaaacccccccccccccjkkkrssssssllllccccccaaaccccc
abccccccccccaaaaaaaaccccccccaaaacccccccaaaaaaaaacaacaaaaaaaaaacaaaccccccccccaaacaaccccccccccccccccccccccccjjkkrrsuuussslllllcccccaaccccc
abccaaacccccaaaaacccccccccccaaaaccccccaaaaaaaaaacccccaaaaaaaaaacaaccccccccccaacccacccccccccccccccccccccjjjjjjrrrsuuuussslllllmcccddacccc
abcccaaaccaccacaaaccccccccccccccccccccaaaaaaaccccccccccaaaaaaaaccccccaacccccccccccaaaaacccccccccccccccjjjjjjrrrruuuuuusssllmmmmmddddcccc
abccaaaaaaaacccaaaccccccccccccccccaaacccccaaaccccccccccccaaacccccccccaacccccccccccaaaaacccccccccccccjjjjjrrrrrruuuxuuussqqqqmmmmmdddcccc
abcaaaaaaaacccaaaaaacaaaaaccccccaaaaaaccccaaacccaaccccccccaaccccccaaaaaaaaccaaacccaaaaaaccccccccccccjjjjrrrrrruuuxxxuuuqqqqqqqmmmdddcccc
abaaaaaaaaaccccaaaaacaaaaaccccccaaaaaaaaccccccaaaaaaccccccccccccccaaaaaaaaccaaacaaaaaaaacccccccccccjjjjrrrtttuuuuxxxyvvvvvqqqqmmmdddcccc
abaaaaaaaaaccaaaaaaacaaaaaaccccccaaaaaaaacccccaaaaaaccccccccccccccccaaaaccaaaaaaaaaaaaaacccccccccaaiijqqqrttttuuuxxyyvvvvvvvqqmmmdddcccc
abcaaaaaaaaccaaaaaaaaaaaaaacccccaaaaaaaacccccccaaaacccccaaaaccccccccaaaaacaaaaaaaaccaaccccccccccaaaiiiqqqttttxxxxxxyyyyyyvvvqqmmmdddcccc
abcccaaaaaaacaaaaaaaaaaaaaacccccaaaaaaaaaaaccccaaaaccccaaaaacccccccaaaaaacaaaaaaacccccccccccccccaaaiiiqqqtttxxxxxxxyyyyyyvvqqqmmmdddcccc
SbcccaacccaccccaaacacccaaacccccccccaaaaaaaaacccaccaccccaaaaaaccccccaaccaacccaaaaaccccccccccccccccaaiiiiqqtttxxxxEzzzyyyyvvvqqqmmmddccccc
abccaaaccccccccaaccccccccccccccccccaaaaaaaaccccccccccccaaaaaaccccccccccccccaaacaaaccaacccccccccccccciiiqqqttttxxxyyyyyvvvvqqqmmmdddccccc
abccccccccccccccccccccccccccccccccaaaaaaaccccccccccccccaaaaaacccccccccccccccaacccccaaaaaaaccccccccccciiiqqqttttxxyyyyyvvvrrrnnneeecccccc
abcaaaaccccccccccccccccccccccccccaaaaaaaaccccccccccccccccaacccccccccccccccccccccccccaaaaacccccccccccciiiqqqqttxxyyyyyyyvvrrnnnneeecccccc
abcaaaaacccccccccccccccccccccccccaaaacaaacccaccaaacccccccccccccccccccccccccaaaccccaaaaaaaccccccccccccciiiqqqttwwyywwyyywwrrnnneeeccccccc
abaaaaaacccaccaccccccccccccccccccaaaaccaacccaaaaaaccccccccccccccccaaaccccaaaaaacccaaaaaaaacccccccccccciiiqqqtswwwwwwwwwwwrrnnneeeccccccc
abaaaaaacccaaaaccccccccaaaacccccccaaacccccccaaaaaacccccccccccccccaaaaaaccaaaaaacccaaaaaaaacaaccccccaaciiiqppsswwwwsswwwwwrrrnneeeccccccc
abcaaaaacccaaaaacccccccaaaacccccccccccccccccaaaaaaaccccccccccccccaaaaaaccaaaaaacccccaaaaaaaaaccccccaaaahhpppssswwsssswwwwrrrnneeeacccccc
abcaaaccccaaaaaacccccccaaaaccccccccccccccccaaaaaaaaccccccccccccccaaaaacccaaaaaccccccaacaaaaaaaaccaaaaaahhpppsssssssssrrrrrrnnneeeacccccc
abccccccccaaaaaaccccccccaacccccccccccccccccaaaaaaaaccccaacccccccccaaaaaccaaaaacccccccccaaaaaaaaccaaaaachhpppssssssoosrrrrrrnnneeeaaacccc
abccccccccccaaccccccccccccccccaaaaaccccccaacccaaacccaaaaacccccccccaacaacccccccccccccccccaaaaaaacccaaaaahhhppppssppooooorroonnffeaaaacccc
abaaccccccccccccccccccccccccccaaaaaccccccaacccaaaccccaaaaacccccccccccccccccccccccccccaacaaaaacccccaacaahhhppppppppoooooooooonfffaaaacccc
abaccccccccccccccccccccccccccaaaaaacccaaaaaaaacccccccaaaaaccccccccccccccccccccccccaaaaaaaaaaaccccccccccchhhpppppppgggoooooooffffaacccccc
abaccccccccccccccccccccccccccaaaaaacccaaaaaaaaccccccaaaaaccccccacccaacccccccccccccaaaaaccccaaccccccccccchhhhhhggggggggfffffffffaaacccccc
abaacccccccccccccccccccccccccaaaaaacccccaaaacccccccccaaaacccaacaacaaacccccccccccccaaaaaaacccccccccccccccchhhhgggggggggffffffffccaacccccc
abcccccccaacccccccccccccccccccaaaccccccaaaaaccccccccaaaaccaaaacaaaaacccccccccccccaaaaaaaaccccccccccccccccchhhggggaaaagffffffcccccccccccc
abcccccccaacccccccccccccaacccccccccccccaaaaaaccaaccccaaaaaaaaacaaaaaacccccccaaaacaaaaaaaacccccccccccaacccccccaaaacaaaacccccccccccccccccc
abccccaaaaaaaacccccccaacaaaccccccccccccaaccaacaaaacccaaaaaaaacaaaaaaaaccccccaaaaccacaaaccaaaccccaaaaaacccccccaacccaaaacccccccccccccaaaaa
abccccaaaaaaaacccccccaaaaaccccccccccccccccccccaaaaccccaaaaaaacaaaaaaaaccccccaaaaccccaaaccaaaaaccaaaaaaaacccccccccccaaaccccccccccccccaaaa
abccccccaaaaccccccccccaaaaaaccccccccccccccccccaaaacccaaaaaaaaaaccaaccccccccccaacccccccccaaaaacccaaaaaaaacccccccccccaaaccccccccccccccaaaa
abcccccaaaaaacccccccaaaaaaaacccccccccccccccccccccccaaaaaaaaaaaaaaaacccccccccccccccccccccaaaaaacccaaaaaaaccccccccccccccccccccccccccaaaaaa

A 2022/12/solve.zig => 2022/12/solve.zig +190 -0
@@ 0,0 1,190 @@
const std = @import("std");
const fs = std.fs;
const heap = std.heap;
const io = std.io;
const math = std.math;
const mem = std.mem;
const process = std.process;
const testing = std.testing;

const Point = struct {
    i: usize,
    j: usize,

    pub fn eql(self: Point, other: Point) bool {
        return self.i == other.i and self.j == other.j;
    }

    fn heuristic(self: Point, other: Point) usize {
        const di = math.absCast(
            @intCast(isize, self.i) - @intCast(isize, other.i),
        );
        const dj = math.absCast(
            @intCast(isize, self.j) - @intCast(isize, other.j),
        );
        return di + dj;
    }
};

const Cell = struct {
    point: Point,
    priority: usize,

    pub fn compare(_: void, lhs: Cell, rhs: Cell) math.Order {
        return math.order(lhs.priority, rhs.priority);
    }
};

const Search = struct {
    map: [41][136]u8,
    frontier: Frontier,
    came_from: CameFrom,
    cost_so_far: CostSoFar,

    const Frontier = std.PriorityQueue(Cell, void, Cell.compare);
    const CameFrom = std.AutoHashMap(Point, Point);
    const CostSoFar = std.AutoHashMap(Point, usize);

    pub fn init(alloc: mem.Allocator) !Search {
        return Search{
            .map = undefined,
            .frontier = Frontier.init(alloc, {}),
            .came_from = CameFrom.init(alloc),
            .cost_so_far = CostSoFar.init(alloc),
        };
    }

    pub fn deinit(self: *Search) void {
        self.frontier.deinit();
        self.came_from.deinit();
        self.cost_so_far.deinit();
    }

    pub fn findPoint(self: Search, height: u8) ?Point {
        return p: for (self.map) |row, i| {
            const j = mem.indexOfScalar(u8, &row, height) orelse continue;
            break :p .{ .i = i, .j = j };
        } else null;
    }

    pub fn findDistance(self: *Search, start: Point, goal: Point) !usize {
        self.frontier.len = 0;
        self.came_from.clearRetainingCapacity();
        self.cost_so_far.clearRetainingCapacity();

        try self.frontier.add(.{ .point = start, .priority = 0 });
        try self.came_from.put(start, start);
        try self.cost_so_far.put(start, 0);

        var point_buf: [4]Point = undefined;
        while (self.frontier.removeOrNull()) |current| {
            if (current.point.eql(goal)) break;

            const cost = self.cost_so_far.get(current.point).? + 1;
            const neighbors = self.getNeighbors(&point_buf, current.point);
            for (neighbors) |next| {
                const next_cost = self.cost_so_far.get(next) orelse math.maxInt(usize);
                if (cost < next_cost) {
                    try self.cost_so_far.put(next, cost);
                    const priority = cost + next.heuristic(goal);
                    try self.frontier.add(.{
                        .point = next,
                        .priority = priority,
                    });
                    try self.came_from.put(next, current.point);
                }
            }
        }

        var distance: usize = 0;
        var current = goal;
        while (!current.eql(start)) {
            current = self.came_from.get(current) orelse break;
            distance += 1;
        }

        return distance;
    }

    fn getNeighbors(self: Search, buffer: []Point, center: Point) []Point {
        const height = self.map[center.i][center.j];
        var k: usize = 0;
        if (center.i > 0) {
            const i = center.i - 1;
            const j = center.j;
            if (self.map[i][j] <= height + 1) {
                buffer[k] = .{ .i = i, .j = j };
                k += 1;
            }
        }
        if (center.j > 0) {
            const i = center.i;
            const j = center.j - 1;
            if (self.map[i][j] <= height + 1) {
                buffer[k] = .{ .i = i, .j = j };
                k += 1;
            }
        }
        if (center.i < 40) {
            const i = center.i + 1;
            const j = center.j;
            if (self.map[i][j] <= height + 1) {
                buffer[k] = .{ .i = i, .j = j };
                k += 1;
            }
        }
        if (center.j < 135) {
            const i = center.i;
            const j = center.j + 1;
            if (self.map[i][j] <= height + 1) {
                buffer[k] = .{ .i = i, .j = j };
                k += 1;
            }
        }
        return buffer[0..k];
    }
};

pub fn main() !void {
    const stdout = io.getStdOut().writer();

    var gpa: heap.GeneralPurposeAllocator(.{}) = .{};
    defer _ = gpa.deinit();
    const alloc = gpa.allocator();

    var args = process.args();
    _ = args.next();
    const filename = args.next() orelse @panic("error: missing input arg.");

    var buffer: [41 * 137]u8 = undefined;
    const content = try fs.cwd().readFile(filename, &buffer);

    var search = try Search.init(alloc);
    defer search.deinit();

    for (search.map) |*row, i| {
        const offset = i * 137;
        mem.copy(u8, row, content[offset .. offset + 136]);
    }

    const start = search.findPoint('S') orelse unreachable;
    const goal = search.findPoint('E') orelse unreachable;

    search.map[start.i][start.j] = 'a';
    search.map[goal.i][goal.j] = 'z';

    const result1 = try search.findDistance(start, goal);
    try stdout.print("solution 1: {d}\n", .{result1});

    var result2 = result1;
    for (search.map) |row, i| {
        for (row) |height, j| {
            if (height == 'a') {
                const begin: Point = .{ .i = i, .j = j };
                const dist = try search.findDistance(begin, goal);
                if (dist != 0 and dist < result2) result2 = dist;
            }
        }
    }
    try stdout.print("solution 2: {d}\n", .{result2});
}

M build.zig => build.zig +1 -0
@@ 54,6 54,7 @@ pub fn build(builder: *Builder) !void {
        .{ .year = "2022", .day = "09" },
        .{ .year = "2022", .day = "10" },
        .{ .year = "2022", .day = "11" },
        .{ .year = "2022", .day = "12" },
    };

    for (problems) |*problem| {