Part two took me longer than it should have because i kept mixing up my col
s and row
s .
Part 1
const std = @import("std");
const input = @embedFile("input.txt");
const map_width = 50;
const map_height = 50;
const MapPos = struct {
row: usize,
col: usize,
};
pub fn main() !void {
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
const map = try parseMap(arena.allocator());
var antinodes = std.AutoHashMap(MapPos, void).init(arena.allocator());
var frequencies = map.iterator();
while (frequencies.next()) |entry| {
const positions = entry.value_ptr.items;
for (positions, 0..) |pos_a, i| {
for (positions[i + 1 ..]) |pos_b| {
if (locateAntiNode(pos_a, pos_b)) |anti_a| {
try antinodes.put(anti_a, {});
}
if (locateAntiNode(pos_b, pos_a)) |anti_b| {
try antinodes.put(anti_b, {});
}
}
}
}
std.log.info("{d}", .{antinodes.count()});
}
/// Returns null if the anti node is out of map bounds.
fn locateAntiNode(a: MapPos, b: MapPos) ?MapPos {
return MapPos{
.row = offset(a.row, b.row) orelse return null,
.col = offset(a.col, b.col) orelse return null,
};
}
fn offset(a: usize, b: usize) ?usize {
const res = if (a > b)
a + (a - b)
else if (b - a > a)
null
else
a - (b - a);
return if (res < 50) res else null;
}
fn parseMap(allocator: std.mem.Allocator) !std.AutoHashMap(u8, std.ArrayListUnmanaged(MapPos)) {
var map = std.AutoHashMap(u8, std.ArrayListUnmanaged(MapPos)).init(allocator);
var line_iter = std.mem.tokenizeScalar(u8, input, '\n');
var row: usize = 0;
while (line_iter.next()) |line| {
for (line, 0..) |ch, col| {
if (ch == '.') continue;
std.debug.assert(std.ascii.isAlphanumeric(ch));
const gop = try map.getOrPutValue(ch, .empty);
try gop.value_ptr.append(allocator, MapPos{
.row = row,
.col = col,
});
}
row += 1;
}
return map;
}
Part 2
const std = @import("std");
const input = @embedFile("input.txt");
const map_width = 50;
const map_height = 50;
const MapPos = struct {
row: usize,
col: usize,
pub fn offset(pos: MapPos, d_row: i32, d_col: i32) ?MapPos {
const row: i32 = @intCast(pos.row);
const col: i32 = @intCast(pos.col);
const s_row = row + d_row;
const s_col = col + d_col;
if (s_row < 0 or s_row >= map_height or s_col < 0 or s_col >= map_width) {
return null;
}
return MapPos{
.row = @intCast(s_row),
.col = @intCast(s_col),
};
}
};
pub fn main() !void {
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
const map = try parseMap(arena.allocator());
var antinodes = std.AutoHashMap(MapPos, void).init(arena.allocator());
var frequencies = map.iterator();
while (frequencies.next()) |entry| {
const positions = entry.value_ptr.items;
for (positions, 0..) |pos_a, i| {
for (positions[i + 1 ..]) |pos_b| {
var d_col = @as(i32, @intCast(pos_a.col)) - @as(i32, @intCast(pos_b.col));
var d_row = @as(i32, @intCast(pos_a.row)) - @as(i32, @intCast(pos_b.row));
const gcd = std.math.gcd(@abs(d_col), @abs(d_row));
d_col = @divExact(d_col, @as(i32, @intCast(gcd)));
d_row = @divExact(d_row, @as(i32, @intCast(gcd)));
var antinode = pos_a;
while (true) {
try antinodes.put(antinode, {});
antinode = antinode.offset(d_row, d_col) orelse break;
}
d_col = -d_col;
d_row = -d_row;
antinode = pos_a;
while (true) {
try antinodes.put(antinode, {});
antinode = antinode.offset(d_row, d_col) orelse break;
}
}
}
}
std.log.info("{d}", .{antinodes.count()});
}
/// Returns null if the antinode is out of map bounds.
fn locateAntiNode(a: MapPos, b: MapPos) ?MapPos {
return MapPos{
.row = offset(a.row, b.row) orelse return null,
.col = offset(a.col, b.col) orelse return null,
};
}
fn offset(a: usize, b: usize) ?usize {
const res = if (a > b)
a + (a - b)
else if (b - a > a)
return null
else
a - (b - a);
return if (res < 50) res else null;
}
fn parseMap(allocator: std.mem.Allocator) !std.AutoHashMap(u8, std.ArrayListUnmanaged(MapPos)) {
var map = std.AutoHashMap(u8, std.ArrayListUnmanaged(MapPos)).init(allocator);
var line_iter = std.mem.tokenizeScalar(u8, input, '\n');
var row: usize = 0;
while (line_iter.next()) |line| {
for (line, 0..) |ch, col| {
if (ch == '.') continue;
std.debug.assert(std.ascii.isAlphanumeric(ch));
const gop = try map.getOrPutValue(ch, .empty);
try gop.value_ptr.append(allocator, MapPos{
.row = row,
.col = col,
});
}
row += 1;
}
return map;
}