-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathday08pt2.zig
114 lines (98 loc) · 3.43 KB
/
day08pt2.zig
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
const std = @import("std");
const input = @embedFile("input08.txt");
const w = std.mem.indexOfScalar(u8, input, '\n').?;
const h = input.len / (w + 1);
const Vec2 = struct {
x: i16,
y: i16,
const Self = @This();
pub inline fn is_in_bounds(self: Self) bool {
return self.x >= 0 and self.x < w and self.y >= 0 and self.y < h;
}
pub inline fn add(self: Self, other: Self) Self {
return .{ .x = self.x + other.x, .y = self.y + other.y };
}
pub inline fn sub(self: Self, other: Self) Self {
return .{ .x = self.x - other.x, .y = self.y - other.y };
}
pub inline fn div_exact(self: Self, divisor: i16) Self {
return .{ .x = @divExact(self.x, divisor), .y = @divExact(self.y, divisor) };
}
};
fn gcd(in_a: i16, in_b: i16) i16 {
if (in_a == 0 or in_b == 0) return 0;
var a = in_a;
var b = in_b;
while (b != 0) {
const tmp = b;
b = @mod(a, b);
a = tmp;
}
return a;
}
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}).init;
defer if (gpa.deinit() != .ok) @panic("GPA LEAK");
const alloc = gpa.allocator();
var antennas = std.AutoHashMapUnmanaged(u8, std.ArrayListUnmanaged(Vec2)).empty;
defer {
var antennas_iter = antennas.valueIterator();
while (antennas_iter.next()) |list| list.deinit(alloc);
antennas.deinit(alloc);
}
// Find antennas and store their positions.
for (0..h) |uy| {
for (0..w) |ux| {
switch (input[uy * (w + 1) + ux]) {
'0'...'9', 'A'...'Z', 'a'...'z' => |c| {
const gop_res = try antennas.getOrPut(alloc, c);
if (!gop_res.found_existing) gop_res.value_ptr.* = .empty;
try gop_res.value_ptr.append(alloc, .{
.x = @intCast(ux),
.y = @intCast(uy),
});
},
else => {},
}
}
}
var antinodes = std.AutoHashMapUnmanaged(Vec2, void).empty;
defer antinodes.deinit(alloc);
// Calculate and store unique antinode positions.
var same_freq_antennas = antennas.valueIterator();
while (same_freq_antennas.next()) |positions| {
for (positions.items[0..positions.items.len - 1], 0..) |a, a_idx| {
for (positions.items[a_idx + 1..positions.items.len]) |b| {
// Start at a and step in the direction of b until out of bounds.
var dir = b.sub(a);
dir = dir.div_exact(gcd(
dir.x * std.math.sign(dir.x),
dir.y * std.math.sign(dir.y),
));
var c = a;
while (c.is_in_bounds()) {
try antinodes.put(alloc, c, {});
c = c.add(dir);
}
// Repeat, but go in the direction of b to a.
dir = a.sub(b);
dir = dir.div_exact(gcd(
dir.x * std.math.sign(dir.x),
dir.y * std.math.sign(dir.y),
));
c = a;
while (c.is_in_bounds()) {
try antinodes.put(alloc, c, {});
c = c.add(dir);
}
}
}
}
std.debug.print("{d}\n", .{antinodes.count()});
}
test "decls" {
std.testing.refAllDecls(@This());
}
test "gcd" {
try std.testing.expectEqual(21, gcd(1071, 462));
}