Day 1: Historian Hysteria

Megathread guidelines

  • Keep top level comments as only solutions, if you want to say something other than a solution put it in a new post. (replies to comments can be whatever)
  • You can send code in code blocks by using three backticks, the code, and then three backticks or use something such as https://blocks.programming.dev/ if you prefer sending it through a URL

FAQ

  • hosaka@programming.dev
    link
    fedilink
    arrow-up
    1
    ·
    23 days ago

    Zig

    const std = @import("std");
    const List = std.ArrayList;
    const Map = std.AutoHashMap;
    
    const splitSeq = std.mem.splitSequence;
    const splitScalar = std.mem.splitScalar;
    const parseInt = std.fmt.parseInt;
    const print = std.debug.print;
    const sort = std.sort.block;
    
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    const alloc = gpa.allocator();
    
    const Answer = struct {
        distance: u32,
        similarity: u32,
    };
    
    fn lessThan(_: void, lhs: []const u8, rhs: []const u8) bool {
        return std.mem.lessThan(u8, lhs, rhs);
    }
    
    pub fn solve(input: []const u8) !Answer {
        var rows = splitScalar(u8, input, '\n');
        var left_list = List([]const u8).init(alloc);
        defer left_list.deinit();
        var right_list = List([]const u8).init(alloc);
        defer right_list.deinit();
    
        // PART 1
    
        // split the rows into two lists
        while (rows.next()) |row| {
            var sides = splitSeq(u8, row, "   ");
            try left_list.append(sides.next() orelse break);
            try right_list.append(sides.next() orelse break);
        }
        _ = left_list.pop(); // last null
    
        // sort both lists
        sort([]const u8, left_list.items, {}, lessThan);
        sort([]const u8, right_list.items, {}, lessThan);
    
        var distance: u32 = 0;
        for (left_list.items, right_list.items) |left, right| {
            distance += @abs(try parseInt(i32, left, 10) - try parseInt(i32, right, 10));
        }
    
        // PART 2
        var right_scores = Map(i32, u32).init(alloc);
        defer right_scores.deinit();
    
        // count number of item appearances in the right list
        for (right_list.items) |item| {
            const value = try parseInt(i32, item, 10);
            const result = try right_scores.getOrPut(value);
            if (!result.found_existing) {
                result.value_ptr.* = 1;
            } else {
                result.value_ptr.* += 1;
            }
        }
    
        // sum up similarity between items in left list and right list scores
        var similarity: u32 = 0;
        for (left_list.items) |item| {
            const value = try parseInt(i32, item, 10);
            const result = right_scores.get(value) orelse 0;
            similarity += @as(u32, @intCast(value)) * result;
        }
        return Answer{ .distance = distance, .similarity = similarity };
    }
    
    pub fn main() !void {
        const answer = try solve(@embedFile("input.txt"));
        print("Part 1: {d}\n", .{answer.distance});
        print("Part 2: {d}\n", .{answer.similarity});
    }
    
    test "test input" {
        const answer = try solve(@embedFile("test.txt"));
        try std.testing.expectEqual(answer.distance, 11);
        try std.testing.expectEqual(answer.similarity, 31);
    }