const std = @import("std");
const ArrayList = std.ArrayList;
const Vec2 = struct {
x: i32,
y: i32,
};
pub fn solve_part1(allocator: std.mem.Allocator, file: []const u8) !void {
var grid = ArrayList([]u8).init(allocator);
var walked = ArrayList([]u8).init(allocator);
var inputs = try std.fs.cwd().openFile(file, .{});
var buffered_reader = std.io.bufferedReader(inputs.reader());
var in_stream = buffered_reader.reader();
var buffer: [1024]u8 = undefined;
while (try in_stream.readUntilDelimiterOrEof(&buffer, '\n')) |line| {
var line_copy = try allocator.dupe(u8, line);
var empty = try allocator.alloc(u8, line_copy.len);
@memset(empty, 0);
try grid.append(line_copy);
try walked.append(empty);
}
walk_beam(grid, &walked, .{ .x = 1, .y = 0 }, .{ .x = 0, .y = 0 });
var part1_result: u64 = 0;
for (walked.items) |l| {
for (l) |c| {
if (c > 0) part1_result += 1;
}
@memset(l, 0);
}
std.log.info("Part 1 result: {d}", .{part1_result});
var part2_result: u64 = 0;
for (0..grid.items[0].len) |start_pos_x| {
walk_beam(grid, &walked, .{ .x = 0, .y = 1 }, .{ .x = @intCast(start_pos_x), .y = 0 });
var h: u64 = 0;
for (walked.items) |l| {
for (l) |c| {
if (c > 0) h += 1;
}
@memset(l, 0);
}
part2_result = @max(part2_result, h);
}
for (0..grid.items[0].len) |start_pos_x| {
walk_beam(grid, &walked, .{ .x = 0, .y = -1 }, .{ .x = @intCast(start_pos_x), .y = @intCast(grid.items.len - 1) });
var h: u64 = 0;
for (walked.items) |l| {
for (l) |c| {
if (c > 0) h += 1;
}
@memset(l, 0);
}
part2_result = @max(part2_result, h);
}
for (0..grid.items.len) |start_pos_y| {
walk_beam(grid, &walked, .{ .x = -1, .y = 0 }, .{ .y = @intCast(start_pos_y), .x = @intCast(grid.items[0].len - 1) });
var h: u64 = 0;
for (walked.items) |l| {
for (l) |c| {
if (c > 0) h += 1;
}
@memset(l, 0);
}
part2_result = @max(part2_result, h);
}
for (0..grid.items.len) |start_pos_y| {
walk_beam(grid, &walked, .{ .x = 1, .y = 0 }, .{ .y = @intCast(start_pos_y), .x = 0 });
var h: u64 = 0;
for (walked.items) |l| {
for (l) |c| {
if (c > 0) h += 1;
}
@memset(l, 0);
}
part2_result = @max(part2_result, h);
}
std.log.info("Part 2 result: {d}", .{part2_result});
}
fn walk_beam(grid: ArrayList([]u8), walked: *ArrayList([]u8), direction: Vec2, position: Vec2) void {
var walk_pos = position;
var walk_dir = direction;
while (walk_pos.x < walked.items[0].len and walk_pos.x >= 0 and walk_pos.y < walked.items.len and walk_pos.y >= 0) {
var wx = @as(usize, @intCast(walk_pos.x));
var wy = @as(usize, @intCast(walk_pos.y));
var flag = dir_to_bit_flag(walk_dir);
if (walked.items[wy][wx] & flag == flag) {
break;
}
walked.items[wy][wx] |= dir_to_bit_flag(walk_dir);
var cur = grid.items[wy][wx];
if (cur == '/') {
walk_dir = forward_mirror(walk_dir);
} else if (cur == '\\') {
walk_dir = backward_mirror(walk_dir);
}
if (cur == '-') {
var p = Vec2{ .x = walk_pos.x - 1, .y = walk_pos.y };
walk_beam(grid, walked, .{ .x = -1, .y = 0 }, p);
p.x += 2;
walk_beam(grid, walked, .{ .x = 1, .y = 0 }, p);
break;
} else if (cur == '|') {
var p = Vec2{ .x = walk_pos.x, .y = walk_pos.y - 1 };
walk_beam(grid, walked, .{ .x = 0, .y = -1 }, p);
p.y += 2;
walk_beam(grid, walked, .{ .x = 0, .y = 1 }, p);
break;
}
walk_pos.x += @intCast(walk_dir.x);
walk_pos.y += @intCast(walk_dir.y);
}
}
fn forward_mirror(dir: Vec2) Vec2 {
if (dir.x == 0 and dir.y == 1) {
return .{ .x = -1, .y = 0 };
} else if (dir.x == 0 and dir.y == -1) {
return .{ .x = 1, .y = 0 };
} else if (dir.x == 1 and dir.y == 0) {
return .{ .x = 0, .y = -1 };
} else if (dir.x == -1 and dir.y == 0) {
return .{ .x = 0, .y = 1 };
}
std.log.err("Bad dir: x {d} y {d}", .{ dir.x, dir.y });
std.os.exit(1);
return .{};
}
fn backward_mirror(dir: Vec2) Vec2 {
if (dir.x == 0 and dir.y == 1) {
return .{ .x = 1, .y = 0 };
} else if (dir.x == 0 and dir.y == -1) {
return .{ .x = -1, .y = 0 };
} else if (dir.x == 1 and dir.y == 0) {
return .{ .x = 0, .y = 1 };
} else if (dir.x == -1 and dir.y == 0) {
return .{ .x = 0, .y = -1 };
}
std.log.err("Bad dir: x {d} y {d}", .{ dir.x, dir.y });
std.os.exit(1);
return .{};
}
fn dir_to_bit_flag(dir: Vec2) u8 {
if (dir.x == 1 and dir.y == 0) {
return 2;
} else if (dir.x == -1 and dir.y == 0) {
return 4;
} else if (dir.x == 0 and dir.y == 1) {
return 8;
} else if (dir.x == 0 and dir.y == -1) {
return 16;
}
return 0;
}