const std = @import("std");
const PATH = "inputs/day09.txt";
pub fn first(allocator: std.mem.Allocator) !isize {
const input = try std.fs.cwd().readFileAlloc(allocator, PATH, 512 * 512);
defer allocator.free(input);
const oasis = try parseInput(allocator, input);
defer {
for (oasis) |line| {
allocator.free(line);
}
allocator.free(oasis);
}
var ret: isize = 0;
for (oasis) |nums| {
var curr_nums = nums;
// we will store the diffs here
var new_nums = try std.ArrayList(NumType).initCapacity(allocator, nums.len - 1);
defer new_nums.deinit();
while (true) {
var all_zero: bool = true;
// store every last item, sum of them is the missing next one
ret += curr_nums[curr_nums.len - 1];
for (1..curr_nums.len) |i| {
const diff = curr_nums[i] - curr_nums[i - 1];
if (diff != 0) all_zero = false;
new_nums.appendAssumeCapacity(diff);
}
if (all_zero) break;
curr_nums = new_nums.items;
try new_nums.resize(0);
}
}
return ret;
}
pub fn second(allocator: std.mem.Allocator) !isize {
const input = try std.fs.cwd().readFileAlloc(allocator, PATH, 512 * 512);
defer allocator.free(input);
const oasis = try parseInput(allocator, input);
defer {
for (oasis) |line| {
allocator.free(line);
}
allocator.free(oasis);
}
var ret: isize = 0;
for (oasis) |nums| {
var curr_nums = nums;
// we will store the diffs here
var new_nums = try std.ArrayList(NumType).initCapacity(allocator, nums.len - 1);
defer new_nums.deinit();
// this is for storing first item from each row
var firsts = std.ArrayList(NumType).init(allocator);
defer firsts.deinit();
while (true) {
var all_zero: bool = true;
try firsts.append(curr_nums[0]);
for (1..curr_nums.len) |i| {
const diff = curr_nums[i] - curr_nums[i - 1];
if (diff != 0) all_zero = false;
new_nums.appendAssumeCapacity(diff);
}
if (all_zero) break;
curr_nums = new_nums.items;
try new_nums.resize(0);
}
// We go through first items backwards, subtracting the cummulative value from
// each previous one to calculate the missing first item.
var c: isize = 0;
var i: usize = firsts.items.len;
while (i > 0) : (i -= 1) {
c = firsts.items[i - 1] - c;
}
ret += c;
}
return ret;
}
test "day09a" {
try std.testing.expectEqual(@as(isize, 1684566095), try first(std.testing.allocator));
}
test "day09b" {
try std.testing.expectEqual(@as(isize, 1136), try second(std.testing.allocator));
}
const NumType = isize;
const Oasis = [][]NumType;
fn parseInput(allocator: std.mem.Allocator, input: []const u8) !Oasis {
var lines = std.mem.splitScalar(u8, input, '\n');
var oasis = std.ArrayList([]isize).init(allocator);
defer oasis.deinit();
var num_line = std.ArrayList(isize).init(allocator);
defer num_line.deinit();
while (lines.next()) |line| {
if (line.len == 0) break;
var items = std.mem.tokenizeScalar(u8, line, ' ');
while (items.next()) |num| {
const n = try std.fmt.parseInt(NumType, num, 10);
try num_line.append(n);
}
try oasis.append(try allocator.dupe(NumType, num_line.items));
try num_line.resize(0);
}
return oasis.toOwnedSlice();
}
const test_input =
\\0 3 6 9 12 15
\\1 3 6 10 15 21
\\10 13 16 21 30 45
;