const std = @import("std");
const PATH = "inputs/day01.txt";
const InputType = i24;
pub fn first(allocator: std.mem.Allocator) !usize {
// Get input
const INPUT_SIZE = 1000 * 14; // lines*line_length
var buf: [INPUT_SIZE]u8 = undefined;
const input = try std.fs.cwd().readFile(PATH, &buf);
const lists = try parseInput(allocator, input);
defer allocator.free(lists.left);
defer allocator.free(lists.right);
// Sort both lists
std.sort.pdq(InputType, lists.left, {}, std.sort.asc(InputType));
std.sort.pdq(InputType, lists.right, {}, std.sort.asc(InputType));
// Calculate total distance
var total_distance: usize = 0;
for (lists.left, lists.right) |left, right| {
const distance = @abs(left - right);
total_distance += distance;
}
return total_distance;
}
pub fn second(allocator: std.mem.Allocator) !usize {
// Get input
const INPUT_SIZE = 1000 * 14; // lines*line_length
var buf: [INPUT_SIZE]u8 = undefined;
const input = try std.fs.cwd().readFile(PATH, &buf);
const lists = try parseInput(allocator, input);
defer allocator.free(lists.left);
defer allocator.free(lists.right);
// Sort right list for efficient matching
std.sort.pdq(InputType, lists.right, {}, comptime std.sort.asc(InputType));
// Calculate similarity score
var total_score: usize = 0;
for (lists.left) |left_num| {
var matches: usize = 0;
for (lists.right) |right_num| {
if (right_num > left_num) break; // No more possible matches
if (right_num == left_num) matches += 1;
}
total_score += @as(usize, @intCast(left_num)) * matches;
}
return total_score;
}
fn parseInput(allocator: std.mem.Allocator, input: []const u8) !struct {
left: []InputType,
right: []InputType,
} {
var left_list = std.ArrayList(InputType).init(allocator);
errdefer left_list.deinit();
var right_list = std.ArrayList(InputType).init(allocator);
errdefer right_list.deinit();
var lines = std.mem.tokenize(u8, input, "\n");
while (lines.next()) |line| {
var numbers = std.mem.tokenize(u8, line, " \t");
if (numbers.next()) |left| {
try left_list.append(try std.fmt.parseInt(InputType, left, 10));
}
if (numbers.next()) |right| {
try right_list.append(try std.fmt.parseInt(InputType, right, 10));
}
}
std.debug.assert(left_list.items.len == right_list.items.len);
return .{
.left = try left_list.toOwnedSlice(),
.right = try right_list.toOwnedSlice(),
};
}
test "day01a" {
try std.testing.expectEqual(@as(usize, 1660292), try first(std.testing.allocator));
}
test "day01b" {
try std.testing.expectEqual(@as(usize, 22776016), try second(std.testing.allocator));
}