const std = @import("std");
const path = "data/day05/input.txt";
const RetType = u16;
const grid_size = 1000;
const max_grid_value = u2;
const Vents = [grid_size][grid_size]max_grid_value;
const CoordType = i20;
const Coord = struct { x: CoordType, y: CoordType };
fn countVents(directions: []const Coord, nodiag: bool) anyerror!RetType {
const input = @embedFile(path);
var lines = std.mem.split(u8, input, "\n");
var vts: Vents = [_][grid_size]max_grid_value{[_]max_grid_value{0} ** grid_size} ** grid_size;
var counter: RetType = 0;
while (lines.next()) |line| {
if (line.len == 0) continue;
var crop_line = std.mem.tokenize(u8, line, " -> ");
// parse coordinates
var l: [2]Coord = undefined;
var idx: usize = 0;
while (crop_line.next()) |cl| : (idx += 1) {
var coords = std.mem.tokenize(u8, cl, ",");
l[idx].x = try std.fmt.parseUnsigned(CoordType, coords.next().?, 10);
l[idx].y = try std.fmt.parseUnsigned(CoordType, coords.next().?, 10);
}
// check if diagonal lines count or not
if (nodiag and !((l[0].x == l[1].x) or (l[0].y == l[1].y))) continue;
// setup lines
const dir = try getDirection(l, directions);
while ((l[0].x != l[1].x + dir.x) or (l[0].y != l[1].y + dir.y)) : ({
l[0].x += dir.x;
l[0].y += dir.y;
}) {
var v = vts[@intCast(usize, l[0].x)][@intCast(usize, l[0].y)];
if (v == 1) {
counter += 1;
}
v +|= 1;
vts[@intCast(usize, l[0].x)][@intCast(usize, l[0].y)] = v;
}
}
return counter;
}
fn getDirection(c: [2]Coord, directions: []const Coord) !Coord {
var min = try manhattan(c[0], c[1]);
for (directions) |d| {
if ((try manhattan(Coord{ .x = c[0].x + d.x, .y = c[0].y + d.y }, c[1])) < min) {
return d;
}
}
unreachable;
}
fn manhattan(f: Coord, s: Coord) !CoordType {
const xdiff = try std.math.absInt(f.x - s.x);
const ydiff = try std.math.absInt(f.y - s.y);
return xdiff + ydiff;
}
pub fn first(allocator: ?std.mem.Allocator) anyerror!RetType {
_ = allocator;
const directions = [_]Coord{
.{ .x = -1, .y = 0 },
.{ .x = 1, .y = 0 },
.{ .x = 0, .y = -1 },
.{ .x = 0, .y = 1 },
};
return try countVents(directions[0..], true);
}
pub fn main() anyerror!void {
var timer = try std.time.Timer.start();
const ret = try first(null);
const f = timer.lap() / 1000;
try std.testing.expectEqual(ret, @as(RetType, 8060));
std.debug.print("Day 5a result: {d} \t\ttime: {d}us\n", .{ ret, f });
}
test "day05a" {
try std.testing.expectEqual(@as(RetType, 8060), try first(std.testing.allocator));
}