const std = @import("std");

const Str = []const u8;

const PATH = "input/day03.txt";

pub fn first(allocator: std.mem.Allocator) !usize {
    return try coordCounter(allocator, @embedFile(PATH));
}

pub fn second(allocator: std.mem.Allocator) !usize {
    return try roboCoordCounter(allocator, @embedFile(PATH));
}

const Coord = [2]i8;

fn coordCounter(allocator: std.mem.Allocator, in: Str) !usize {
    var crd: Coord = .{ 0, 0 };

    var seen = std.AutoHashMap(Coord, void).init(allocator);
    defer seen.deinit();

    try seen.put(crd, {});

    for (in) |ch| {
        switch (ch) {
            '^' => crd[1] += 1,
            'v' => crd[1] -= 1,
            '>' => crd[0] += 1,
            '<' => crd[0] -= 1,
            else => {},
        }
        try seen.put(crd, {});
    }

    return seen.count();
}

fn roboCoordCounter(allocator: std.mem.Allocator, in: Str) !usize {
    var santa: Coord = .{ 0, 0 };
    var robo_santa: Coord = .{ 0, 0 };

    var seen = std.AutoHashMap(Coord, void).init(allocator);
    defer seen.deinit();

    try seen.put(santa, {});

    for (in) |ch, idx| {
        if (idx % 2 == 0) {
            switch (ch) {
                '^' => santa[1] += 1,
                'v' => santa[1] -= 1,
                '>' => santa[0] += 1,
                '<' => santa[0] -= 1,
                else => {},
            }
            try seen.put(santa, {});
        } else {
            switch (ch) {
                '^' => robo_santa[1] += 1,
                'v' => robo_santa[1] -= 1,
                '>' => robo_santa[0] += 1,
                '<' => robo_santa[0] -= 1,
                else => {},
            }
            try seen.put(robo_santa, {});
        }
    }

    return seen.count();
}

test "Santa" {
    try std.testing.expectEqual(@as(usize, 2), try coordCounter(std.testing.allocator, ">"));
    try std.testing.expectEqual(@as(usize, 4), try coordCounter(std.testing.allocator, "^>v<"));
    try std.testing.expectEqual(@as(usize, 2), try coordCounter(std.testing.allocator, "^v^v^v^v^v"));
}

test "Robo-Santa" {
    try std.testing.expectEqual(@as(usize, 3), try roboCoordCounter(std.testing.allocator, "^v"));
    try std.testing.expectEqual(@as(usize, 3), try roboCoordCounter(std.testing.allocator, "^>v<"));
    try std.testing.expectEqual(@as(usize, 11), try roboCoordCounter(std.testing.allocator, "^v^v^v^v^v"));
}

test "day03a" {
    try std.testing.expectEqual(@as(usize, 2565), try first(std.testing.allocator));
}

test "day03b" {
    try std.testing.expectEqual(@as(usize, 2639), try second(std.testing.allocator));
}