aoc2015day14.zig
· 4.7 KiB · Zig
Raw
const std = @import("std");
const mem = std.mem;
const fs = std.fs;
const print = std.debug.print;
const ParseError = error{
RanOutOfWords,
};
const Parser = struct {
it: mem.SplitIterator(u8, .scalar),
fn fromString(str: []const u8) Parser {
return Parser{
.it = mem.splitScalar(u8, str, ' '),
};
}
fn take(self: *Parser) ![]const u8 {
const wordo = self.it.next();
if (wordo) |word| {
return word;
} else {
return ParseError.RanOutOfWords;
}
}
fn skip(self: *Parser, cnt: usize) void {
for (0..cnt) |_| {
_ = self.it.next();
}
}
fn takeAsNumber(self: *Parser, Type: type) !Type {
const wordo = self.it.next();
if (wordo) |word| {
return std.fmt.parseInt(Type, word, 10);
} else {
return ParseError.RanOutOfWords;
}
}
};
const Raindeer = struct {
speed: usize,
flight: usize,
rest: usize,
fn distanceAfter(self: Raindeer, sec: usize) usize {
const chunk_time = self.flight + self.rest;
const chunk_dist = self.speed * self.flight;
const chunked = chunk_dist * (sec / chunk_time);
const left = @mod(sec, chunk_time);
const rest = if (left > self.flight) self.speed * self.flight else self.speed * left;
return chunked + rest;
}
};
fn getLines(path: []const u8, alloc: mem.Allocator) !std.ArrayList(Raindeer) {
const file = fs.cwd().openFile(path, .{}) catch |err| {
std.log.err("Failed to open file {s}", .{@errorName(err)});
return err;
};
defer file.close();
var raindeer = std.ArrayList(Raindeer).init(alloc);
while (file.reader().readUntilDelimiterOrEofAlloc(alloc, '\n', std.math.maxInt(usize)) catch |err| {
std.log.err("Failed to read line: {s}", .{@errorName(err)});
return err;
}) |line| {
defer alloc.free(line);
var words = Parser.fromString(line);
words.skip(3);
const speed = try words.takeAsNumber(usize);
words.skip(2);
const flight = try words.takeAsNumber(usize);
words.skip(6);
const rest = try words.takeAsNumber(usize);
try raindeer.append(.{
.speed = speed,
.flight = flight,
.rest = rest,
});
}
return raindeer;
}
fn part1(raindeer: std.ArrayList(Raindeer)) !void {
var score: usize = 0;
for (raindeer.items) |rd| {
score = @max(score, rd.distanceAfter(2503));
}
print("Part1: {d}\n", .{score});
}
const RaindeerState = struct {
raindeer: Raindeer,
running: bool,
time: usize,
distance: usize,
points: usize,
fn fromRaindeer(rnd: Raindeer) RaindeerState {
return .{
.raindeer = rnd,
.running = true,
.time = 0,
.distance = 0,
.points = 0,
};
}
fn tick(self: *RaindeerState) void {
if (self.running) {
self.distance += self.raindeer.speed;
self.time += 1;
if (self.time >= self.raindeer.flight) {
self.time = 0;
self.running = false;
}
} else {
self.time += 1;
if (self.time >= self.raindeer.rest) {
self.time = 0;
self.running = true;
}
}
}
};
fn run(raindeer: std.ArrayList(Raindeer), alloc: mem.Allocator, sec: usize) !usize {
var states = std.ArrayList(*RaindeerState).init(alloc);
defer {
for (states.items) |state| {
alloc.destroy(state);
}
states.deinit();
}
for (raindeer.items) |rnd| {
const state = try alloc.create(RaindeerState);
state.* = RaindeerState.fromRaindeer(rnd);
try states.append(state);
}
for (0..sec) |_| {
var max_dist: usize = 0;
for (states.items) |state| {
state.tick();
max_dist = @max(max_dist, state.distance);
}
for (states.items) |state| {
if (state.distance == max_dist)
state.points += 1;
}
}
var max_points: usize = 0;
for (states.items) |state| {
max_points = @max(max_points, state.points);
}
return max_points;
}
fn part2(raindeer: std.ArrayList(Raindeer), alloc: mem.Allocator) !void {
const score = try run(raindeer, alloc, 2503);
print("Part2: {d}\n", .{score});
}
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const alloc = gpa.allocator();
const filename = "day14.txt";
var raindeer = try getLines(filename, alloc);
defer raindeer.deinit();
try part1(raindeer);
try part2(raindeer, alloc);
}
1 | const std = @import("std"); |
2 | const mem = std.mem; |
3 | const fs = std.fs; |
4 | const print = std.debug.print; |
5 | |
6 | const ParseError = error{ |
7 | RanOutOfWords, |
8 | }; |
9 | |
10 | const 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 | |
44 | const 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 | |
59 | fn 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 | |
89 | fn 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 | |
99 | const 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 | |
134 | fn 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 | |
168 | fn 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 | |
173 | pub 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 |