const std = @import("std");

const Str = []const u8;

const INPUT = "1113122113";

pub fn first(allocator: std.mem.Allocator) !usize {
    return try countLAS(allocator, INPUT, 40);
}

pub fn second(allocator: std.mem.Allocator) !usize {
    return try countLAS(allocator, INPUT, 50);
}

fn countLAS(allocator: std.mem.Allocator, in: Str, round: usize) !usize {
    var arena = std.heap.ArenaAllocator.init(allocator);
    defer arena.deinit();

    var al = std.ArrayList(u8).init(allocator);
    defer al.deinit();

    var next: Str = in;

    var i: usize = 0;
    while (i < round) : (i += 1) {
        next = try std.fmt.allocPrint(arena.allocator(), "{s}", .{try genLAS(&al, next)});
        al.clearRetainingCapacity();
    }

    return next.len;
}

fn genLAS(ret: *std.ArrayList(u8), in: Str) !Str {
    const offset = 49; // to convert the number to a char

    var count: u8 = 0;
    var last: u8 = in[0];

    var idx: usize = 1;
    while (idx < in.len) : (idx += 1) {
        if (last == in[idx]) {
            count += 1;
        } else {
            try ret.appendSlice(&[_]u8{ count + offset, last });
            count = 0;
            last = in[idx];
        }
    }

    try ret.append(count + offset);
    try ret.append(last);

    return ret.items;
}

test "Examples" {
    var al = std.ArrayList(u8).init(std.testing.allocator);
    defer al.deinit();

    // try std.testing.expectEqualStrings("11", try genLAS(&al, "1"));
    try std.testing.expectEqualStrings("21", try genLAS(&al, "11"));
    al.clearRetainingCapacity();
    try std.testing.expectEqualStrings("1211", try genLAS(&al, "21"));
    al.clearRetainingCapacity();
    try std.testing.expectEqualStrings("111221", try genLAS(&al, "1211"));
    al.clearRetainingCapacity();
    try std.testing.expectEqualStrings("312211", try genLAS(&al, "111221"));
}

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

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