1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
|
const std = @import("std");
const Vec = @Vector(2, i16);
const Input = struct {
s: Vec,
robots: []Robot,
};
const Robot = struct {
pos: Vec,
vel: Vec,
};
const test_input =
\\p=0,4 v=3,-3
\\p=6,3 v=-1,-3
\\p=10,3 v=-1,2
\\p=2,0 v=2,-1
\\p=0,0 v=1,3
\\p=3,0 v=-2,-2
\\p=7,6 v=-1,-3
\\p=3,0 v=-1,-2
\\p=9,3 v=2,3
\\p=7,3 v=-1,2
\\p=2,4 v=2,-3
\\p=9,5 v=-3,-3
\\
;
pub fn parse(allocator: std.mem.Allocator, data: []const u8) !Input {
const size: struct { w: i8, h: i8 } = if (data.ptr == test_input.ptr) .{ .w = 11, .h = 7 } else .{ .w = 101, .h = 103 };
var lines = std.mem.splitScalar(u8, data, '\n');
var robots = std.ArrayList(Robot).init(allocator);
while (lines.next()) |line| {
if (line.len == 0) break;
var it = std.mem.tokenizeAny(u8, line, "pv=, ");
const px = it.next() orelse return error.InvalidInput;
const py = it.next() orelse return error.InvalidInput;
const vx = it.next() orelse return error.InvalidInput;
const vy = it.next() orelse return error.InvalidInput;
// std.debug.print("{s} {s} {s} {s}\n", .{ px, py, vx, vy });
try robots.append(.{
.pos = .{
try std.fmt.parseInt(i8, px, 10),
try std.fmt.parseInt(i8, py, 10),
},
.vel = .{
try std.fmt.parseInt(i8, vx, 10),
try std.fmt.parseInt(i8, vy, 10),
},
});
}
return .{ .s = .{ size.w, size.h }, .robots = robots.items };
}
test "part1" {
var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
defer arena.deinit();
const output = try part1(arena.allocator(), try parse(arena.allocator(), test_input));
try std.testing.expectEqual(12, output);
}
pub fn part1(allocator: std.mem.Allocator, input: Input) !u32 {
const robots = try allocator.alloc(Robot, input.robots.len);
@memcpy(robots, input.robots);
for (0..100) |_| {
for (robots) |*robot| {
robot.pos = @mod(robot.pos + robot.vel, input.s);
}
}
var quadrants = @Vector(4, u32){ 0, 0, 0, 0 };
for (robots) |robot| {
if (@reduce(.Or, robot.pos == input.s / @as(Vec, @splat(2))))
continue;
const idx = @reduce(.Add, @select(u2, robot.pos < input.s / @as(Vec, @splat(2)), .{ 0, 0 }, .{ 2, 1 }));
quadrants[idx] += 1;
}
return @reduce(.Mul, quadrants);
}
test "part2" {
var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
defer arena.deinit();
const output = try part2(arena.allocator(), try parse(arena.allocator(), test_input));
std.debug.print("got {}\n", .{output});
try std.testing.expectEqual(2, output);
}
pub fn part2(allocator: std.mem.Allocator, input: Input) !u32 {
const robots = try allocator.alloc(Robot, input.robots.len);
@memcpy(robots, input.robots);
var i: usize = 0;
const map = try allocator.alloc(u8, @intCast(@reduce(.Mul, input.s)));
return while (true) : (i += 1) {
@memset(map, 0);
for (robots) |*robot| {
robot.pos = @mod(robot.pos + robot.vel, input.s);
map[@intCast(robot.pos[1] * input.s[0] + robot.pos[0])] +|= 1;
}
var buf: [(101 + 1) * 103]u8 = undefined;
var fbs = std.io.fixedBufferStream(&buf);
var out = fbs.writer();
for (0..@intCast(input.s[1])) |y| {
for (0..@intCast(input.s[0])) |x| {
try out.print("{c}", .{switch (map[y * @as(u32, @intCast(input.s[0])) + x]) {
0 => '.',
1...9 => |c| c + '0',
10...10 + 26 - 1 => |c| c - 10 + 'a',
10 + 26...10 + 26 + 26 - 1 => |c| c - 10 + 'A',
else => '+',
}});
}
try out.print("\n", .{});
}
std.debug.print("{s}", .{fbs.getWritten()});
try std.io.getStdIn().reader().skipUntilDelimiterOrEof('\n');
if (false) break i;
};
}
|