const std = @import("std");
const INPUT = "14,3,1,0,9,5";
const Str = []const u8;
pub fn first(allocator: ?std.mem.Allocator) anyerror!usize {
return getLast(allocator.?, INPUT, 2020, u11);
}
pub fn second(allocator: ?std.mem.Allocator) anyerror!usize {
return getLast(allocator.?, INPUT, 30_000_000, u25);
}
fn getLast(allocator: std.mem.Allocator, input: Str, limit: usize, comptime ItemType: anytype) !usize {
var spoken = std.ArrayList(ItemType).init(allocator);
defer spoken.deinit();
// Zero means the number was not spoken yet.
try spoken.appendNTimes(0, limit);
var last: ItemType = undefined;
// Fill in starting numbers.
var starting = std.mem.tokenize(u8, input, ",");
var round: ItemType = 1;
while (starting.next()) |st| : (round += 1) {
const num = try std.fmt.parseUnsigned(ItemType, st, 0);
spoken.items[num] = round;
last = num;
}
// Van Eck Sequence
round -= 1;
while (round < limit) : (round += 1) {
const next = round - if (spoken.items[last] != 0) spoken.items[last] else round;
spoken.items[last] = round;
last = next;
}
return @intCast(usize, last);
}
test "day15a" {
try std.testing.expectEqual(@as(usize, 614), try first(std.testing.allocator));
}
test "day15b" {
try std.testing.expectEqual(@as(usize, 1065), try second(std.testing.allocator));
}