const std = @import("std");
const PATH = "input/day14.txt";
const Str = []const u8;
pub fn first(allocator: std.mem.Allocator) !usize {
_ = allocator;
const RACE_TIME = 2503;
var max: usize = 0;
var lines = std.mem.tokenize(u8, @embedFile(PATH), "\n");
while (lines.next()) |line| {
var words = std.mem.tokenize(u8, line, " ");
for (.{ "deer", "can", "fly" }) |_| {
_ = words.next();
}
const speed = try std.fmt.parseUnsigned(usize, words.next().?, 10);
for (.{ "km/s", "for" }) |_| {
_ = words.next();
}
const duration = try std.fmt.parseUnsigned(usize, words.next().?, 10);
for (.{ "seconds,", "but", "then", "must", "rest", "for" }) |_| {
_ = words.next();
}
const rest = try std.fmt.parseUnsigned(usize, words.next().?, 10);
const full_runs = RACE_TIME / (duration + rest);
const left_time = RACE_TIME % (duration + rest);
const run: usize = speed * duration * full_runs + std.math.min(duration, left_time) * speed;
if (run > max) max = run;
}
return max;
}
pub fn second(allocator: std.mem.Allocator) !usize {
const RACE_TIME = 2503;
var deers = try parseInput(allocator, @embedFile(PATH));
defer allocator.free(deers);
var lead: usize = 0;
var time: usize = 0;
while (time < RACE_TIME) : (time += 1) {
for (deers) |*deer| {
const my_time = time % (deer.duration + deer.rest);
if (my_time < deer.duration) deer.pos += deer.speed;
if (deer.pos > lead) lead = deer.pos;
}
// give reward points
for (deers) |*deer| {
if (deer.pos == lead) deer.points += 1;
}
}
var max: usize = 0;
for (deers) |deer| {
if (deer.points > max) max = deer.points;
}
return max;
}
const Deer = struct {
speed: usize,
duration: usize,
rest: usize,
pos: usize = 0,
points: usize = 0,
};
fn parseInput(allocator: std.mem.Allocator, in: Str) ![]Deer {
var deers = std.ArrayList(Deer).init(allocator);
var lines = std.mem.tokenize(u8, in, "\n");
while (lines.next()) |line| {
var words = std.mem.tokenize(u8, line, " ");
for (.{ "deer", "can", "fly" }) |_| {
_ = words.next();
}
const speed = try std.fmt.parseUnsigned(usize, words.next().?, 10);
for (.{ "km/s", "for" }) |_| {
_ = words.next();
}
const duration = try std.fmt.parseUnsigned(usize, words.next().?, 10);
for (.{ "seconds,", "but", "then", "must", "rest", "for" }) |_| {
_ = words.next();
}
const rest = try std.fmt.parseUnsigned(usize, words.next().?, 10);
try deers.append(.{ .speed = speed, .duration = duration, .rest = rest });
}
return try deers.toOwnedSlice();
}
test "day14a" {
try std.testing.expectEqual(@as(usize, 2660), try first(std.testing.allocator));
}
test "day14b" {
try std.testing.expectEqual(@as(usize, 1256), try second(std.testing.allocator));
}
const test_input =
\\Comet can fly 14 km/s for 10 seconds, but then must rest for 127 seconds.
\\Dancer can fly 16 km/s for 11 seconds, but then must rest for 162 seconds.
;