Last active 1720089306

aoc2015day14.zig Raw
1const std = @import("std");
2const mem = std.mem;
3const fs = std.fs;
4const print = std.debug.print;
5
6const ParseError = error{
7 RanOutOfWords,
8};
9
10const Parser = struct {
11 it: mem.SplitIterator(u8, .scalar),
12
13 fn fromString(str: []const u8) Parser {
14 return Parser{
15 .it = mem.splitScalar(u8, str, ' '),
16 };
17 }
18
19 fn take(self: *Parser) ![]const u8 {
20 const wordo = self.it.next();
21 if (wordo) |word| {
22 return word;
23 } else {
24 return ParseError.RanOutOfWords;
25 }
26 }
27
28 fn skip(self: *Parser, cnt: usize) void {
29 for (0..cnt) |_| {
30 _ = self.it.next();
31 }
32 }
33
34 fn takeAsNumber(self: *Parser, Type: type) !Type {
35 const wordo = self.it.next();
36 if (wordo) |word| {
37 return std.fmt.parseInt(Type, word, 10);
38 } else {
39 return ParseError.RanOutOfWords;
40 }
41 }
42};
43
44const Raindeer = struct {
45 speed: usize,
46 flight: usize,
47 rest: usize,
48
49 fn distanceAfter(self: Raindeer, sec: usize) usize {
50 const chunk_time = self.flight + self.rest;
51 const chunk_dist = self.speed * self.flight;
52 const chunked = chunk_dist * (sec / chunk_time);
53 const left = @mod(sec, chunk_time);
54 const rest = if (left > self.flight) self.speed * self.flight else self.speed * left;
55 return chunked + rest;
56 }
57};
58
59fn getLines(path: []const u8, alloc: mem.Allocator) !std.ArrayList(Raindeer) {
60 const file = fs.cwd().openFile(path, .{}) catch |err| {
61 std.log.err("Failed to open file {s}", .{@errorName(err)});
62 return err;
63 };
64 defer file.close();
65
66 var raindeer = std.ArrayList(Raindeer).init(alloc);
67
68 while (file.reader().readUntilDelimiterOrEofAlloc(alloc, '\n', std.math.maxInt(usize)) catch |err| {
69 std.log.err("Failed to read line: {s}", .{@errorName(err)});
70 return err;
71 }) |line| {
72 defer alloc.free(line);
73 var words = Parser.fromString(line);
74 words.skip(3);
75 const speed = try words.takeAsNumber(usize);
76 words.skip(2);
77 const flight = try words.takeAsNumber(usize);
78 words.skip(6);
79 const rest = try words.takeAsNumber(usize);
80 try raindeer.append(.{
81 .speed = speed,
82 .flight = flight,
83 .rest = rest,
84 });
85 }
86 return raindeer;
87}
88
89fn part1(raindeer: std.ArrayList(Raindeer)) !void {
90 var score: usize = 0;
91
92 for (raindeer.items) |rd| {
93 score = @max(score, rd.distanceAfter(2503));
94 }
95
96 print("Part1: {d}\n", .{score});
97}
98
99const RaindeerState = struct {
100 raindeer: Raindeer,
101 running: bool,
102 time: usize,
103 distance: usize,
104 points: usize,
105
106 fn fromRaindeer(rnd: Raindeer) RaindeerState {
107 return .{
108 .raindeer = rnd,
109 .running = true,
110 .time = 0,
111 .distance = 0,
112 .points = 0,
113 };
114 }
115
116 fn tick(self: *RaindeerState) void {
117 if (self.running) {
118 self.distance += self.raindeer.speed;
119 self.time += 1;
120 if (self.time >= self.raindeer.flight) {
121 self.time = 0;
122 self.running = false;
123 }
124 } else {
125 self.time += 1;
126 if (self.time >= self.raindeer.rest) {
127 self.time = 0;
128 self.running = true;
129 }
130 }
131 }
132};
133
134fn run(raindeer: std.ArrayList(Raindeer), alloc: mem.Allocator, sec: usize) !usize {
135 var states = std.ArrayList(*RaindeerState).init(alloc);
136 defer {
137 for (states.items) |state| {
138 alloc.destroy(state);
139 }
140 states.deinit();
141 }
142
143 for (raindeer.items) |rnd| {
144 const state = try alloc.create(RaindeerState);
145 state.* = RaindeerState.fromRaindeer(rnd);
146 try states.append(state);
147 }
148
149 for (0..sec) |_| {
150 var max_dist: usize = 0;
151 for (states.items) |state| {
152 state.tick();
153 max_dist = @max(max_dist, state.distance);
154 }
155
156 for (states.items) |state| {
157 if (state.distance == max_dist)
158 state.points += 1;
159 }
160 }
161 var max_points: usize = 0;
162 for (states.items) |state| {
163 max_points = @max(max_points, state.points);
164 }
165 return max_points;
166}
167
168fn part2(raindeer: std.ArrayList(Raindeer), alloc: mem.Allocator) !void {
169 const score = try run(raindeer, alloc, 2503);
170 print("Part2: {d}\n", .{score});
171}
172
173pub fn main() !void {
174 var gpa = std.heap.GeneralPurposeAllocator(.{}){};
175 defer _ = gpa.deinit();
176 const alloc = gpa.allocator();
177
178 const filename = "day14.txt";
179 var raindeer = try getLines(filename, alloc);
180 defer raindeer.deinit();
181
182 try part1(raindeer);
183 try part2(raindeer, alloc);
184}
185